@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,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: waterx-sdk-integration
|
|
3
|
-
description: Use when integrating @waterx/sdk into an app, keeper, or bot — wiring a WaterX client, creating and funding a wxa account, building perp or prediction transactions, or debugging a WaterX build/simulate failure. Covers the required waterxConfigUrl
|
|
3
|
+
description: Use when integrating @waterx/sdk into an app, keeper, or bot — wiring a WaterX client, creating and funding a wxa account, building perp or prediction transactions, or debugging a WaterX build/simulate failure. Covers the required waterxConfigUrl option, the config-derived oracle fed set, the build→simulate→execute discipline, and the aborts integrators hit first.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Integrating `@waterx/sdk`
|
|
7
7
|
|
|
8
8
|
WaterX is a perpetual futures DEX and prediction market on Sui. The SDK **builds
|
|
9
9
|
transactions**; it never signs on your behalf and never reads `process.env`. Every
|
|
10
|
-
chain-specific value comes from a config JSON
|
|
10
|
+
chain-specific value comes from a config JSON _you_ supply.
|
|
11
11
|
|
|
12
12
|
Work the steps in order. Each one has a decision you must make explicitly — the SDK has
|
|
13
13
|
no defaults for the first two on purpose, so that every environment runs the same build
|
|
@@ -15,11 +15,11 @@ and differs only by configuration.
|
|
|
15
15
|
|
|
16
16
|
## Step 1 — Choose the entry point
|
|
17
17
|
|
|
18
|
-
| You need
|
|
19
|
-
|
|
|
20
|
-
| Both product lines
|
|
21
|
-
| Perpetuals only
|
|
22
|
-
| Prediction markets only
|
|
18
|
+
| You need | Import | Client |
|
|
19
|
+
| ----------------------- | ------------------------ | ------------------------ |
|
|
20
|
+
| Both product lines | `@waterx/sdk` | `WaterXClient.create()` |
|
|
21
|
+
| Perpetuals only | `@waterx/sdk/perp` | `PerpClient.create()` |
|
|
22
|
+
| Prediction markets only | `@waterx/sdk/prediction` | `PredictClient.create()` |
|
|
23
23
|
|
|
24
24
|
The umbrella exposes three namespaces: `client.account` (shared wxa account + funding),
|
|
25
25
|
`client.perp`, `client.predict`. The two lines have colliding builder names
|
|
@@ -33,17 +33,15 @@ pnpm add @waterx/sdk @mysten/sui @mysten/bcs # the two Mysten packages are pee
|
|
|
33
33
|
|
|
34
34
|
Node ≥ 22. ESM and CJS both resolve.
|
|
35
35
|
|
|
36
|
-
## Step 2 — Supply the
|
|
36
|
+
## Step 2 — Supply the config URL
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
39
|
import { WaterXClient } from "@waterx/sdk";
|
|
40
|
-
import { parseOracleSourceList } from "@waterx/sdk/oracle";
|
|
41
40
|
|
|
42
41
|
const client = await WaterXClient.create({
|
|
43
42
|
network: "TESTNET",
|
|
44
43
|
waterxConfigUrl: process.env.WATERX_CONFIG_URL, // REQUIRED — no default, no env fallback
|
|
45
|
-
|
|
46
|
-
pythApiKey: process.env.PYTH_API_KEY, // required iff the set includes 'pyth_lazer_rule'
|
|
44
|
+
pythApiKey: process.env.PYTH_API_KEY, // required iff the config wires pyth_lazer_rule
|
|
47
45
|
});
|
|
48
46
|
```
|
|
49
47
|
|
|
@@ -53,28 +51,36 @@ as-is — the SDK appends no `<network>.json` and no git ref. Your app reads the
|
|
|
53
51
|
the SDK never does. Look up ids through the client (`client.perp.getMarket(ticker)`,
|
|
54
52
|
`client.perp.creditType()`, `client.perp.wlpType()`) rather than hardcoding them.
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
**The oracle fed set is DERIVED from that config** — there is no `oracleSource` option
|
|
55
|
+
and no `ORACLE_SOURCE` env var. A source is fed when its block is published, carries at
|
|
56
|
+
least one feed, and is not explicitly `enabled: false`. Every derived source's data is
|
|
57
|
+
fetched and fed in one PTB, and the chain's per-ticker weight tables arbitrate. Read the
|
|
58
|
+
answer for a live deployment with `client.perp.oracleSources`, or before a client exists
|
|
59
|
+
with `deriveOracleSources(config)`.
|
|
58
60
|
|
|
59
|
-
| Source | Notes
|
|
60
|
-
| ----------------- |
|
|
61
|
-
| `
|
|
62
|
-
| `pyth_lazer_rule` | one signed verify per PTB, no per-feed fees; **requires `pythApiKey`** |
|
|
61
|
+
| Source | Notes |
|
|
62
|
+
| ----------------- | -------------------------------------------------------------------------------- |
|
|
63
|
+
| `pyth_lazer_rule` | one signed verify per PTB, no per-feed fees; **requires `pythApiKey`** |
|
|
63
64
|
| `waterx_rule` | first-party TEE quote-center; no credential; browser needs a CORS-allowed origin |
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
(`pyth_rule` — Pyth Core / Hermes — was retired in 5.0.0. Its block is still published
|
|
67
|
+
in the live configs and is inert: it is not a derivable source, so nothing feeds it.)
|
|
68
|
+
|
|
69
|
+
Why derived rather than declared: **the fed set must be a superset of every ticker's
|
|
66
70
|
on-chain weighted rules.** Starving a weighted rule aborts `EMissingPriceSource`; feeding
|
|
67
|
-
an unweighted one is silently dropped.
|
|
68
|
-
|
|
71
|
+
an unweighted one is silently dropped. Because the failure is one-sided, taking every
|
|
72
|
+
source the config wires is the fail-safe answer — and a hand-typed list could only err
|
|
73
|
+
in the fatal direction (the classic being one copied between networks). A weight
|
|
74
|
+
migration is then a config change, never an env edit and never an SDK release.
|
|
69
75
|
|
|
70
|
-
|
|
76
|
+
Inspect what a network actually weights when you are debugging:
|
|
71
77
|
|
|
72
78
|
```bash
|
|
73
79
|
pnpm oracle:aggregates:testnet # per-ticker aggregator sources + weights
|
|
74
80
|
```
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
Want to fail at BOOT rather than at the first trade that needs a missing feed? Pass the
|
|
83
|
+
tickers you care about to `assertOracleWriteCoverage(client.perp, tickers)`.
|
|
78
84
|
|
|
79
85
|
## Step 3 — Ensure a wxa account
|
|
80
86
|
|
|
@@ -134,15 +140,15 @@ const tx = await client.perp.buildPlaceOrderTx({
|
|
|
134
140
|
isStopOrder: false,
|
|
135
141
|
reduceOnly: false,
|
|
136
142
|
size: rawPrice(0.001),
|
|
137
|
-
triggerPrice: undefined,
|
|
143
|
+
triggerPrice: undefined, // omit ⇒ market order
|
|
138
144
|
acceptablePrice: rawPrice(120_000), // slippage cap
|
|
139
145
|
collateralAmount: 5_000_000n,
|
|
140
146
|
},
|
|
141
|
-
preOrders: [],
|
|
147
|
+
preOrders: [], // optional reduce-only TP/SL legs
|
|
142
148
|
});
|
|
143
149
|
|
|
144
150
|
tx.setSender(address);
|
|
145
|
-
await client.perp.simulate(tx);
|
|
151
|
+
await client.perp.simulate(tx); // ALWAYS. Free, and catches every step-2 mistake.
|
|
146
152
|
await client.perp.signAndExecuteTransaction({ transaction: tx, signer });
|
|
147
153
|
```
|
|
148
154
|
|
|
@@ -174,7 +180,7 @@ Stop if you catch yourself doing any of these:
|
|
|
174
180
|
|
|
175
181
|
- **Hardcoding an object id.** It belongs in the config JSON, read via the client.
|
|
176
182
|
- **Writing `BTC/USD` or `BTC`.** Tickers are concatenated: `BTCUSD`, `ETHUSD`, `SUIUSD`.
|
|
177
|
-
(Collateral
|
|
183
|
+
(Collateral _tokens_ keep a plain symbol — `USDC` — and are a different thing.)
|
|
178
184
|
- **Passing a plain number as a price or size.** Wrap in `rawPrice()`. The exception:
|
|
179
185
|
view `basePriceUsd` arguments take a whole-dollar u64 — `parseWholeDollarU64`.
|
|
180
186
|
- **Skipping simulate.** Every failure in the table below is free to find at simulate.
|
|
@@ -194,14 +200,14 @@ Which step a failure sends you back to. The **full messages, causes, and fixes l
|
|
|
194
200
|
one place** — `README.md`'s Troubleshooting table — so that they stay accurate; do not
|
|
195
201
|
re-derive them from here.
|
|
196
202
|
|
|
197
|
-
| Error
|
|
198
|
-
|
|
|
199
|
-
| `loadConfig: no config URL …`
|
|
200
|
-
| `
|
|
201
|
-
| `EMissingPriceSource`
|
|
202
|
-
| `LazerApiKeyMissing …`
|
|
203
|
-
| `EAccountNotFound`
|
|
204
|
-
| `EReplayedSignature`
|
|
203
|
+
| Error | Go back to |
|
|
204
|
+
| --------------------------------------------------------------------- | -------------------------------------------------- |
|
|
205
|
+
| `loadConfig: no config URL …` | Step 2 — `waterxConfigUrl` |
|
|
206
|
+
| `fed set […] has no feed for ticker(s)` (`OracleTickerUnservedError`) | Step 2 — the config's feeds |
|
|
207
|
+
| `EMissingPriceSource` | Step 2 — the fed set is too narrow for that ticker |
|
|
208
|
+
| `LazerApiKeyMissing …` | Step 2 — `pythApiKey` |
|
|
209
|
+
| `EAccountNotFound` | Step 3 — the account id is not on this network |
|
|
210
|
+
| `EReplayedSignature` | Step 5 — an envelope was reused across builds |
|
|
205
211
|
|
|
206
212
|
## Verifying an integration
|
|
207
213
|
|
package/README.md
CHANGED
|
@@ -11,22 +11,22 @@ The perp and prediction lines expose builder functions with **colliding names**
|
|
|
11
11
|
```ts
|
|
12
12
|
import { WaterXClient } from "@waterx/sdk";
|
|
13
13
|
|
|
14
|
-
// waterxConfigUrl
|
|
15
|
-
//
|
|
14
|
+
// waterxConfigUrl is REQUIRED — the SDK has no built-in default and never
|
|
15
|
+
// reads env. The oracle fed set is DERIVED from that config; there is nothing
|
|
16
|
+
// to pick. See "Oracle sources" below.
|
|
16
17
|
const client = await WaterXClient.create({
|
|
17
18
|
network: "TESTNET",
|
|
18
19
|
waterxConfigUrl:
|
|
19
20
|
"https://raw.githubusercontent.com/WaterXProtocol/waterx-config/main/testnet.json",
|
|
20
|
-
|
|
21
|
-
pythApiKey: process.env.PYTH_API_KEY, // required iff 'pyth_lazer_rule' is listed
|
|
21
|
+
pythApiKey: process.env.PYTH_API_KEY, // required iff the config wires pyth_lazer_rule
|
|
22
22
|
});
|
|
23
23
|
client.account.createAccount(tx, { alias }); // shared waterx_account + funding (credit/custody)
|
|
24
24
|
client.perp.buildPlaceOrderTx(params); // perpetuals
|
|
25
25
|
client.predict.placeOrder(tx, params); // prediction markets
|
|
26
26
|
// client.perp / client.predict ARE the line clients — sign/execute on them directly:
|
|
27
27
|
// await client.perp.signAndExecuteTransaction({ transaction: tx, signer })
|
|
28
|
-
// each line can target a different network + URL (
|
|
29
|
-
// WaterXClient.create({
|
|
28
|
+
// each line can target a different network + URL (each derives its own fed set):
|
|
29
|
+
// WaterXClient.create({ perp: { network: "MAINNET", waterxConfigUrl: mainnetUrl }, predict: { network: "TESTNET", waterxConfigUrl: testnetUrl } })
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
> `WaterXClient` is the umbrella entry point. `Client` is kept as a **deprecated alias** for one major cycle.
|
|
@@ -68,11 +68,9 @@ import { Transaction } from "@mysten/sui/transactions";
|
|
|
68
68
|
const client = await WaterXClient.create({
|
|
69
69
|
network: "TESTNET",
|
|
70
70
|
waterxConfigUrl: "https://raw.githubusercontent.com/WaterXProtocol/waterx-config/main/testnet.json",
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
oracleSource: ["pyth_rule", "pyth_lazer_rule"],
|
|
75
|
-
pythApiKey: process.env.PYTH_API_KEY, // required iff 'pyth_lazer_rule' is listed
|
|
71
|
+
// The fed set is derived from this config — nothing to declare. Inspect it
|
|
72
|
+
// with `pnpm oracle:aggregates:testnet`. See "Oracle sources".
|
|
73
|
+
pythApiKey: process.env.PYTH_API_KEY, // required iff the config wires pyth_lazer_rule
|
|
76
74
|
});
|
|
77
75
|
const signer = /* your Ed25519Keypair or wallet Signer */;
|
|
78
76
|
const accountId = "0x..."; // wxa account object id — see "First integration"
|
|
@@ -123,8 +121,7 @@ walkthrough as one runnable file** — being real code, it is covered by `pnpm l
|
|
|
123
121
|
|
|
124
122
|
```bash
|
|
125
123
|
export WATERX_CONFIG_URL=https://raw.githubusercontent.com/WaterXProtocol/waterx-config/main/testnet.json
|
|
126
|
-
export
|
|
127
|
-
export PYTH_API_KEY=... # required whenever pyth_lazer_rule is listed
|
|
124
|
+
export PYTH_API_KEY=... # required iff the config wires pyth_lazer_rule
|
|
128
125
|
pnpm exec tsx examples/quickstart.ts # simulate-only; WATERX_EXECUTE=1 to sign + send
|
|
129
126
|
```
|
|
130
127
|
|
|
@@ -133,10 +130,12 @@ pnpm exec tsx examples/quickstart.ts # simulate-only; WATERX_EXECUTE
|
|
|
133
130
|
built-in default and the SDK never reads `process.env`: your app reads the URL and passes
|
|
134
131
|
it in. Hardcoding object ids instead is the single most common integration mistake.
|
|
135
132
|
|
|
136
|
-
**2 —
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
133
|
+
**2 — Nothing to pick: the fed set is derived.** Every source the config wires (a
|
|
134
|
+
published package with a non-empty feeds map) is fed. That is what keeps the fed set a
|
|
135
|
+
**superset of every ticker's on-chain weighted rules**, which is the property that
|
|
136
|
+
matters — starving a weighted rule aborts `EMissingPriceSource` at simulate, while
|
|
137
|
+
feeding an unweighted one is dropped harmlessly on chain. Inspect what a network
|
|
138
|
+
weights when you are debugging:
|
|
140
139
|
|
|
141
140
|
```bash
|
|
142
141
|
pnpm oracle:aggregates:testnet # per-ticker aggregator sources + weights
|
|
@@ -172,7 +171,7 @@ const accountId = ev ? AccountCreated.parse(ev.bcs).account_object_address : und
|
|
|
172
171
|
|
|
173
172
|
→ [`examples/actions/action-create-account.ts`](./examples/actions/action-create-account.ts)
|
|
174
173
|
|
|
175
|
-
**4 — Fund it.** Collateral must sit
|
|
174
|
+
**4 — Fund it.** Collateral must sit _inside_ the account before an order will fill.
|
|
176
175
|
Deposit is two calls in one PTB — `requestDeposit(coin)` then
|
|
177
176
|
`direct_rule::consume_deposit_direct(req)`.
|
|
178
177
|
|
|
@@ -215,58 +214,64 @@ import { PredictClient } from "@waterx/sdk/prediction";
|
|
|
215
214
|
|
|
216
215
|
const waterxConfigUrl =
|
|
217
216
|
"https://raw.githubusercontent.com/WaterXProtocol/waterx-config/main/testnet.json";
|
|
218
|
-
//
|
|
217
|
+
// The fed set comes from the config — see "Oracle sources".
|
|
219
218
|
const perp = await PerpClient.create("TESTNET", {
|
|
220
219
|
waterxConfigUrl,
|
|
221
|
-
|
|
222
|
-
pythApiKey: process.env.PYTH_API_KEY, // required iff 'pyth_lazer_rule' is listed
|
|
220
|
+
pythApiKey: process.env.PYTH_API_KEY, // required iff the config wires pyth_lazer_rule
|
|
223
221
|
}); // or PerpClient.testnet({ ... })
|
|
224
|
-
const predict = await PredictClient.create("TESTNET", { waterxConfigUrl }); // predict line
|
|
222
|
+
const predict = await PredictClient.create("TESTNET", { waterxConfigUrl }); // predict line has no oracle plane
|
|
225
223
|
```
|
|
226
224
|
|
|
227
225
|
Read-only queries use gRPC `simulateTransaction` (no signer) — the `getX` view helpers, e.g. `await perp.simulate(tx)` or `getMarketData(perp, …)`.
|
|
228
226
|
|
|
229
227
|
## Oracle sources
|
|
230
228
|
|
|
231
|
-
|
|
229
|
+
The fed set is **derived from the deployment config** — there is no `oracleSource` create option and no `ORACLE_SOURCE` env var. A source is fed when its block is published AND carries at least one feed, so mainnet derives `[pyth_lazer_rule, waterx_rule]` and testnet `[waterx_rule]` with no per-environment wiring at all. Each source remains **self-contained** — it owns its own infra + config and does **not** back-stop any other source.
|
|
232
230
|
|
|
233
|
-
|
|
234
|
-
| -------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
235
|
-
| `oracleSource` | `OracleSource \| OracleSource[]` of `'pyth_rule'` \| `'pyth_lazer_rule'` \| `'waterx_rule'` — REQUIRED, no default | The price-update source(s). `'pyth_rule'` = Pyth Core updates (Hermes VAA + per-feed update fees, keyless `hermes.pyth.network`). `'pyth_lazer_rule'` = Pyth Lazer signed updates (ONE `leEcdsa` verify per PTB, no per-feed fees); needs `packages.pyth_lazer_rule` feeds + a `pythApiKey`. `'waterx_rule'` = the first-party WaterX quote-center (Nautilus-TEE, ed25519-signed CEX prices): one signed batch envelope per build, no API key and no per-update fee; needs `packages.waterx_rule` feeds. |
|
|
231
|
+
Why derived rather than declared: the chain arbitrates. Per-ticker weights decide which contributions count, feeding an **unweighted** rule is dropped on-chain, and starving a **weighted** one aborts `EMissingPriceSource`. The failure is one-sided, so a hand-typed list can only err in the fatal direction — the classic being one copied between networks, naming a source that deployment does not carry. The config cannot, because it _is_ what wires the rules. Retired blocks are inert: `pyth_rule` and `pyth_sponsor_rule` still sit in the live configs, and neither is an `ORACLE_SOURCES` member, so neither can ever be derived.
|
|
236
232
|
|
|
237
|
-
|
|
233
|
+
| Source | Fed when | What it is |
|
|
234
|
+
| ----------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
235
|
+
| `pyth_lazer_rule` | `packages.pyth_lazer_rule` is published with feeds | Pyth Lazer signed updates — ONE `leEcdsa` verify per PTB, no per-feed fees. Auth-first, so it needs a `pythApiKey`. |
|
|
236
|
+
| `waterx_rule` | `packages.waterx_rule` is published with feeds | The first-party WaterX quote-center (Nautilus-TEE, ed25519-signed CEX prices): one signed Merkle leaf per ticker, batch-envelope fallback. No API key, no per-update fee. |
|
|
238
237
|
|
|
239
|
-
|
|
238
|
+
`deriveOracleSources(config)` is exported if you need the answer before a client exists (e.g. to pair with `missingOracleCredentials` in a boot assert); `client.oracleSources` is the same value on a live client. (`pyth_rule` — Pyth Core / Hermes — was RETIRED in 5.0.0.)
|
|
240
239
|
|
|
241
|
-
|
|
240
|
+
**Multi-source fed sets.** When the config wires more than one, ONE build fetches and feeds EVERY derived source's data in the same PTB; the chain's per-ticker aggregator **weight tables** decide which contributions count. That asymmetry is what makes weight migrations (Lazer↔waterx coexistence) safe: the derived set is a superset of every ticker's weighted rule set by construction, so weights flip per ticker at any time — a config edit, never an SDK release and never an env edit. (One caveat: waterx's feed call burns a per-symbol signed-timestamp high-water mark regardless of weights — see the replay note below.)
|
|
241
|
+
|
|
242
|
+
**No cross-source fallback.** Construction fails only when the config wires **no** price-update source at all (nothing could ever be priced). A derived source whose feed for a particular ticker is absent is not an error: `refreshOraclePrices` **skips** that ticker and reports it in `OracleRefreshSummary.skipped`, so a sweep over 30 markets does not lose 29 because the 30th is unconfigured. The `build*Tx` composers then fail closed with `OracleTickerUnservedError` on the tickers their specific action depends on — the traded market plus collateral, or **every pool asset** for WLP — unless you pass `allowUnrefreshedPrices: true`. Constant-only tickers need no price update and are exempt. A present-but-wrong feed id is not validated by the SDK; it aborts on-chain at dry-run.
|
|
243
|
+
|
|
244
|
+
Every source's external infra is a **rule-owned per-network table**, never deployment-overridable and never in the config JSON: `LAZER_INFRA` (`src/oracle/rules/pyth-lazer-rule.ts` — Lazer HTTP endpoint, verifier package, per-network channel), `WATERX_INFRA` (`src/oracle/rules/waterx-rule.ts` — testnet `quote-center-staging.waterx.app` / mainnet `quote-center.waterx.app`, accessor `waterxQuoteCenterEndpoint(network)`). For **price READS**, every source reads through its OWN feeds namespace (write set == read set by construction): resolve the per-source served-set/ids with `resolveOracleReadPlan` (`lazer` = integer Lazer ids, `quote_center` = tickers; `readPlanTickers` flattens either) and execute the plan with `readLazerPrices` / `readQuoteCenterPrices` (`src/oracle/read-prices.ts`). `client.pyth` is the access-only `PythAccessConfig` — just the caller-supplied `pythApiKey` / `pythFetch` create options (a secret has no place in a public CDN JSON); `client.waterx` is likewise `WaterxAccessConfig` (`waterxEndpoint` / `waterxFetch` overrides only; fetch policy resolves **`waterxFetch` → built-in defaults** — deliberately no `pythFetch` fallback, sources never share config). See the browser/CORS note below.
|
|
242
245
|
|
|
243
246
|
```ts
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
// validate every value, dedupe, throw operator-actionably) — never a bare
|
|
247
|
-
// split-and-cast, which would hand the strict constructor untrimmed junk.
|
|
248
|
-
import { parseOracleSourceList } from "@waterx/sdk/oracle";
|
|
247
|
+
// Need the fed set before a client exists (boot asserts, health checks)?
|
|
248
|
+
import { deriveOracleSources, missingOracleCredentials } from "@waterx/sdk/oracle";
|
|
249
249
|
|
|
250
|
+
// Per-environment wiring is just the config URL: point an environment at a
|
|
251
|
+
// different config and its fed set follows.
|
|
250
252
|
const perp = await PerpClient.create(network, {
|
|
251
253
|
waterxConfigUrl,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
+
pythApiKey: process.env.PYTH_API_KEY, // required iff that config wires pyth_lazer_rule (auth-first)
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const missing = missingOracleCredentials(deriveOracleSources(config), {
|
|
258
|
+
pythApiKey: process.env.PYTH_API_KEY,
|
|
254
259
|
});
|
|
255
260
|
```
|
|
256
261
|
|
|
257
|
-
This is the coexistence rollout pattern: staging
|
|
262
|
+
This is the coexistence rollout pattern: staging's config wires every source under migration while production's trails until its weight tables move — flipping an environment is a **config** change, never an env edit and never an SDK release.
|
|
258
263
|
|
|
259
264
|
### Adding an oracle source (runbook)
|
|
260
265
|
|
|
261
|
-
Every source plugs in the same way — routing is driven **only** by the
|
|
266
|
+
Every source plugs in the same way — routing is driven **only** by what the deployment config wires (never a config `enabled` flag, never `process.env`):
|
|
262
267
|
|
|
263
|
-
1. **Implement `PriceUpdateRule`** in `src/oracle/rules/<name>-rule.ts` — all port fields (`src/oracle/price-update-rule.ts`): `kind`, `
|
|
268
|
+
1. **Implement `PriceUpdateRule`** in `src/oracle/rules/<name>-rule.ts` — all port fields (`src/oracle/price-update-rule.ts`): `kind`, `credential` (set iff the off-chain fetch needs a caller credential — one object carrying the credential KIND and the rule's OWN error, which the fail-fast pre-check throws and `missingOracleCredentials` reports), `supportedTickers`, `fetchUpdateData`, `narrowUpdateData` (subset a cached whole-universe payload to one build's tickers — a divisible payload returns a per-feed subset, an indivisible one returns itself whole iff fully covered; uncovered ticker → `null` miss), `updateIdentityBySymbol` (iff the on-chain verify is replay-guarded per symbol), `buildUpdateCalls`.
|
|
264
269
|
2. **Register it** in `src/oracle/rule-registry.ts` (`DEFAULT_RULES`) under a new `OracleSource` value — added to `ORACLE_SOURCES` in `price-update-rule.ts` (the union derives from that list; a registry test pins every listed value to a registered rule).
|
|
265
270
|
3. **Publish the on-chain rule package** — its config entry (package ids, per-ticker `feeds`) arrives via the normal `waterx-config` deploy pipeline; type it in `OraclePackages` (`src/oracle/config.ts`).
|
|
266
271
|
4. **Add SDK infra constants** if the source needs external infra that is not part of the config JSON (API endpoints, verifier packages, state objects) — a **rule-owned** per-network table inside the rule's own file, mirroring `LAZER_INFRA` / `WATERX_INFRA` (never on the shared client, never in `oracle/config.ts`). Wire its read-plane served-set/ids into `resolveOracleReadPlan` (`src/oracle/read-plane.ts`).
|
|
267
|
-
5. **
|
|
272
|
+
5. **Publish the block in the config** for the deployments that should feed it — every client on that config picks it up. No consumer code change, no env edit, no SDK re-release.
|
|
268
273
|
|
|
269
|
-
The in-house `waterx_rule` (ed25519 enclave-signed CEX prices, `src/oracle/rules/waterx-rule.ts`) took exactly this path: it pulls one signed Merkle **leaf** per requested ticker from the quote-center (`GET /v1/quotes/leaves?symbols=…`, public read — no auth), then verifies **and** feeds in a single `waterx_rule::collect_single_with_proof` call per collector, so it emits no shared verify step. Each leaf carries its own membership proof and the enclave's signature over the snapshot root, so a PTB rebuilds exactly ONE price item however wide the snapshot was. Against a quote-center with no leaf route (404) it falls back to the older shape — one signature over a whole batch (`GET /v1/quotes/update`) fed through `collect_batch_latest`, which is indivisible and therefore has to rebuild
|
|
274
|
+
The in-house `waterx_rule` (ed25519 enclave-signed CEX prices, `src/oracle/rules/waterx-rule.ts`) took exactly this path: it pulls one signed Merkle **leaf** per requested ticker from the quote-center (`GET /v1/quotes/leaves?symbols=…`, public read — no auth), then verifies **and** feeds in a single `waterx_rule::collect_single_with_proof` call per collector, so it emits no shared verify step. Each leaf carries its own membership proof and the enclave's signature over the snapshot root, so a PTB rebuilds exactly ONE price item however wide the snapshot was. Against a quote-center with no leaf route (404) it falls back to the older shape — one signature over a whole batch (`GET /v1/quotes/update`) fed through `collect_batch_latest`, which is indivisible and therefore has to rebuild _every_ item in the batch in-PTB just to use one symbol's price.
|
|
270
275
|
|
|
271
276
|
On-chain, both entries dispose of failures identically: a **freshness** miss abstains (the other weighted rules cover), and so does a **replayed** signed timestamp (the per-symbol high-water mark of audit F-014 — already recorded means the chain already holds a price at least this fresh, so concurrent builds sharing one snapshot no longer kill each other; only the single-rule `feed_*` entries abort on a replay). A config mismatch, a bad signature, or a signed timestamp **ahead of the on-chain `Clock`** aborts.
|
|
272
277
|
|
|
@@ -275,7 +280,6 @@ On-chain, both entries dispose of failures identically: a **freshness** miss abs
|
|
|
275
280
|
> ```ts
|
|
276
281
|
> const perp = await PerpClient.create(network, {
|
|
277
282
|
> waterxConfigUrl,
|
|
278
|
-
> oracleSource: "waterx_rule",
|
|
279
283
|
> // absolute URL on your own origin; its base path is PRESERVED, so this
|
|
280
284
|
> // fetches https://app.example/api/quote-center/v1/quotes/leaves
|
|
281
285
|
> waterxEndpoint: "https://app.example/api/quote-center",
|
|
@@ -283,7 +287,7 @@ On-chain, both entries dispose of failures identically: a **freshness** miss abs
|
|
|
283
287
|
> });
|
|
284
288
|
> ```
|
|
285
289
|
>
|
|
286
|
-
> Unset, `waterxEndpoint` falls back to the rule-owned `WATERX_INFRA[network]` and `waterxFetch` to the built-in policy (15s timeout, 2 retries) — there is deliberately no `pythFetch` fallback. Both are inert under the Pyth sources. They are also top-level options on the umbrella `WaterXClient.create({
|
|
290
|
+
> Unset, `waterxEndpoint` falls back to the rule-owned `WATERX_INFRA[network]` and `waterxFetch` to the built-in policy (15s timeout, 2 retries) — there is deliberately no `pythFetch` fallback. Both are inert under the Pyth sources. They are also top-level options on the umbrella `WaterXClient.create({ waterxEndpoint, waterxFetch, … })`, which forwards them to the perp line. Node/keeper consumers are unaffected by CORS either way.
|
|
287
291
|
|
|
288
292
|
## Recipes & full surface
|
|
289
293
|
|
|
@@ -294,39 +298,39 @@ To avoid doc drift, per-action usage lives in maintained, lint-checked code rath
|
|
|
294
298
|
- **Prediction recipes:** [`test/prediction/e2e/`](./test/prediction/e2e) — the live reference for `client.predict.*` flows.
|
|
295
299
|
- **Authoritative export list:** [`src/perp/index.ts`](./src/perp/index.ts) (perp) and [`src/prediction/index.ts`](./src/prediction/index.ts) — clients, builders, view helpers, BCS types, and `*Calls` generated namespaces. The package root (`.`) is [`src/sdk.ts`](./src/sdk.ts) (umbrella + flat-perp re-export); the shared base is published at `@waterx/sdk/account` and `@waterx/sdk/oracle`.
|
|
296
300
|
|
|
297
|
-
Perp `build*Tx` helpers are oracle-backed (`async`; they refresh prices before the call) — through whichever
|
|
301
|
+
Perp `build*Tx` helpers are oracle-backed (`async`; they refresh prices before the call) — through whichever sources the deployment config wires, not Pyth specifically. The oracle layer (sources, rules, refresh) lives in [`src/oracle/`](./src/oracle).
|
|
298
302
|
|
|
299
303
|
## Troubleshooting
|
|
300
304
|
|
|
301
305
|
Every row below is a message the SDK or the chain actually emits. Simulate first — all of
|
|
302
306
|
these surface at simulate, before you spend gas.
|
|
303
307
|
|
|
304
|
-
| Message
|
|
305
|
-
|
|
|
306
|
-
| `loadConfig: no config URL — pass opts.waterxConfigUrl`
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `EMissingPriceSource` (Move abort in `aggregator::remove_outliers`)
|
|
310
|
-
| `LazerApiKeyMissing: pyth_lazer_rule requires a Pyth Lazer access token`
|
|
311
|
-
| `EAccountNotFound` (Move abort in `account::borrow_account`)
|
|
312
|
-
| `EReplayedSignature`
|
|
313
|
-
| CORS failure fetching the quote-center (browser only)
|
|
314
|
-
| Ticker lookups return nothing
|
|
315
|
-
| Prices off by 10⁹, or an order fills far from the intended level
|
|
316
|
-
|
|
|
308
|
+
| Message | What it means, and what to do |
|
|
309
|
+
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
310
|
+
| `loadConfig: no config URL — pass opts.waterxConfigUrl` | `waterxConfigUrl` is unset; there is no default and no env fallback. Read the URL in your app and pass it to `create()`. |
|
|
311
|
+
| `this deployment's config wires no price-update source …` | The loaded config publishes no `pyth_lazer_rule` / `waterx_rule` block with feeds, so nothing could ever be priced. Raised at client creation. Check you loaded the config you meant to. |
|
|
312
|
+
| `fed set [...] has no feed for ticker(s): …` (`OracleTickerUnservedError`) | No derived source serves a ticker this build depends on. `refreshOraclePrices` itself SKIPS such tickers; the `build*Tx` composers raise this for the ones their action needs (traded ticker + collateral, or every pool asset for WLP). Add the feed, or pass `allowUnrefreshedPrices: true` to build anyway. Constant-only tickers are exempt. |
|
|
313
|
+
| `EMissingPriceSource` (Move abort in `aggregator::remove_outliers`) | The fed set does not cover that ticker's on-chain weighted rules — starving a weighted rule aborts, feeding an unweighted one is a no-op. Run `pnpm oracle:aggregates:testnet`, then publish the missing source's feeds in the config so it is derived. |
|
|
314
|
+
| `LazerApiKeyMissing: pyth_lazer_rule requires a Pyth Lazer access token` | The config wires `pyth_lazer_rule` but `pythApiKey` was not passed. The SDK never reads `process.env` for it — pass it at client creation. |
|
|
315
|
+
| `EAccountNotFound` (Move abort in `account::borrow_account`) | The `accountId` does not exist on this network — usually a fixture from another deployment, or a Sui address used where a wxa account id belongs. Create one with `client.account.createAccount`. |
|
|
316
|
+
| `EReplayedSignature` | A `waterx_rule` signed timestamp was replayed on a **single-rule `feed_*`** entry, where it aborts. The `build*Tx` composers do NOT use those — they feed through `collect_*`, where a replay ABSTAINS (audit F-014's high-water mark means the chain already holds a price at least that fresh). If you see this, a custom PTB is calling a `feed_*` leg directly. |
|
|
317
|
+
| CORS failure fetching the quote-center (browser only) | `waterx_rule` fetches from the page and your origin is not on the allowlist. Point `waterxEndpoint` at a same-origin proxy; its base path is preserved. Node and keeper consumers are unaffected. |
|
|
318
|
+
| Ticker lookups return nothing | Wrong format. Tickers are concatenated — `BTCUSD`, never `BTC/USD` or `BTC`. Canonical list: the config JSON's `markets` keys. |
|
|
319
|
+
| Prices off by 10⁹, or an order fills far from the intended level | A human-readable number was passed where a raw 1e9-scaled `u64` belongs. Wrap in `rawPrice()`. Exception: view `basePriceUsd` args take a **whole-dollar** u64 — use `parseWholeDollarU64`. |
|
|
320
|
+
| A ticker prices on one network but not another | The two networks wire **different sources**, and the fed set follows the config — mainnet derives `[pyth_lazer_rule, waterx_rule]`, testnet `[waterx_rule]`. This is the drift a hand-declared list used to cause and derivation removes. Confirm per network with `pnpm oracle:aggregates:mainnet`. |
|
|
317
321
|
|
|
318
322
|
## Documentation map
|
|
319
323
|
|
|
320
|
-
| Document
|
|
321
|
-
|
|
|
322
|
-
| [`SKILLS.md`](./SKILLS.md)
|
|
323
|
-
| [`examples/README.md`](./examples/README.md)
|
|
324
|
-
| [`CHANGELOG.md`](./CHANGELOG.md)
|
|
325
|
-
| [`PACKAGES.md`](./PACKAGES.md)
|
|
326
|
-
| [`CLAUDE.md`](./CLAUDE.md)
|
|
327
|
-
| [`test/perp/README.md`](./test/perp/README.md)
|
|
328
|
-
| [`test/prediction/README.md`](./test/prediction/README.md)
|
|
329
|
-
| [`waterx-config`](https://github.com/WaterXProtocol/waterx-config) | The canonical deployment JSON schema
|
|
324
|
+
| Document | What it answers |
|
|
325
|
+
| ------------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
|
326
|
+
| [`SKILLS.md`](./SKILLS.md) | The fixed integration flow, for an agent or a developer |
|
|
327
|
+
| [`examples/README.md`](./examples/README.md) | Every runnable perp recipe, one file per entry point |
|
|
328
|
+
| [`CHANGELOG.md`](./CHANGELOG.md) | What changed per release — **read before upgrading** (see versioning note) |
|
|
329
|
+
| [`PACKAGES.md`](./PACKAGES.md) | The Move packages behind the SDK |
|
|
330
|
+
| [`CLAUDE.md`](./CLAUDE.md) | Architecture and contract surface, for people hacking on the SDK |
|
|
331
|
+
| [`test/perp/README.md`](./test/perp/README.md) | Perp test tiers, fixtures, and known skips |
|
|
332
|
+
| [`test/prediction/README.md`](./test/prediction/README.md) | Prediction test tiers and the live `client.predict.*` reference |
|
|
333
|
+
| [`waterx-config`](https://github.com/WaterXProtocol/waterx-config) | The canonical deployment JSON schema |
|
|
330
334
|
|
|
331
335
|
## Development
|
|
332
336
|
|
|
@@ -337,16 +341,16 @@ pnpm install
|
|
|
337
341
|
pnpm build
|
|
338
342
|
```
|
|
339
343
|
|
|
340
|
-
| Command
|
|
341
|
-
|
|
|
342
|
-
| `pnpm typecheck`
|
|
343
|
-
| `pnpm docs:check`
|
|
344
|
-
| `pnpm test` / `pnpm test:unit`
|
|
345
|
-
| `pnpm test:e2e`
|
|
346
|
-
| `pnpm test:integration`
|
|
347
|
-
| `pnpm lint` / `pnpm format`
|
|
348
|
-
| `pnpm codegen`
|
|
344
|
+
| Command | Use |
|
|
345
|
+
| -------------------------------- | ------------------------------------------------------------------------ |
|
|
346
|
+
| `pnpm typecheck` | Typecheck the whole tree |
|
|
347
|
+
| `pnpm docs:check` | Resolve every relative link in the docs |
|
|
348
|
+
| `pnpm test` / `pnpm test:unit` | Unit tests (perp + prediction) |
|
|
349
|
+
| `pnpm test:e2e` | Testnet simulate e2e (perp + prediction) |
|
|
350
|
+
| `pnpm test:integration` | On-chain integration (needs `SUI_PRIVATE_KEY`; local-only) |
|
|
351
|
+
| `pnpm lint` / `pnpm format` | ESLint + Prettier |
|
|
352
|
+
| `pnpm codegen` | Regenerate `src/generated` from Move |
|
|
349
353
|
| `pnpm oracle:aggregates:testnet` | Per-ticker aggregator sources + weights (diagnose `EMissingPriceSource`) |
|
|
350
|
-
| `pnpm seed:testnet`
|
|
354
|
+
| `pnpm seed:testnet` | Seed prediction testnet fixtures (needs `SUI_PRIVATE_KEY`) |
|
|
351
355
|
|
|
352
356
|
Tests are split per line under `test/perp/` and `test/prediction/`, each with `unit` / `e2e` / `integration` tiers. See the per-line `README.md` in each.
|
|
@@ -71,11 +71,9 @@ export interface WithdrawalQueuePackage {
|
|
|
71
71
|
queue?: string;
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
|
-
* Wormhole infra for the cross-chain credit bridge. `state_id` is the
|
|
75
|
-
*
|
|
76
|
-
* `
|
|
77
|
-
* per-deployment via `WaterXConfig.wormhole` if a deployment ever points
|
|
78
|
-
* elsewhere.
|
|
74
|
+
* Wormhole infra for the cross-chain credit bridge. `state_id` is the shared
|
|
75
|
+
* Sui Wormhole `State` object for the network. Override per-deployment via
|
|
76
|
+
* `WaterXConfig.wormhole` if a deployment ever points elsewhere.
|
|
79
77
|
*/
|
|
80
78
|
export interface WormholeInfraConfig {
|
|
81
79
|
/** Shared Sui Wormhole `State` object. */
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Wormhole / Wormholescan integration for the cross-chain credit bridge.
|
|
3
3
|
*
|
|
4
|
-
* Single source of truth for VAA discovery + (de)serialization
|
|
5
|
-
* `oracle/pyth.ts`'s role for Pyth's Hermes endpoint. Two directions:
|
|
4
|
+
* Single source of truth for VAA discovery + (de)serialization. Two directions:
|
|
6
5
|
*
|
|
7
6
|
* - Mint (EVM → Sui): fetch the signed VAA for an EVM `Deposit` by
|
|
8
7
|
* (emitter chain, emitter address, sequence); the raw bytes feed
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Wormhole / Wormholescan integration for the cross-chain credit bridge.
|
|
4
4
|
*
|
|
5
|
-
* Single source of truth for VAA discovery + (de)serialization
|
|
6
|
-
* `oracle/pyth.ts`'s role for Pyth's Hermes endpoint. Two directions:
|
|
5
|
+
* Single source of truth for VAA discovery + (de)serialization. Two directions:
|
|
7
6
|
*
|
|
8
7
|
* - Mint (EVM → Sui): fetch the signed VAA for an EVM `Deposit` by
|
|
9
8
|
* (emitter chain, emitter address, sequence); the raw bytes feed
|