@waterx/sdk 4.0.0 → 4.1.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.
Files changed (128) hide show
  1. package/README.md +52 -37
  2. package/dist/cjs/src/account/account.js +2 -1
  3. package/dist/cjs/src/account/config.d.ts +0 -16
  4. package/dist/cjs/src/account/funding/balance.d.ts +25 -2
  5. package/dist/cjs/src/account/funding/balance.js +36 -24
  6. package/dist/cjs/src/account/funding/credit.js +6 -10
  7. package/dist/cjs/src/constants.d.ts +15 -1
  8. package/dist/cjs/src/constants.js +18 -4
  9. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  10. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +13 -0
  11. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  12. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.js +31 -0
  13. package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +940 -0
  14. package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +1092 -0
  15. package/dist/cjs/src/oracle/aggregate.d.ts +21 -21
  16. package/dist/cjs/src/oracle/aggregate.js +84 -71
  17. package/dist/cjs/src/oracle/config.d.ts +107 -52
  18. package/dist/cjs/src/oracle/config.js +15 -35
  19. package/dist/cjs/src/oracle/host.d.ts +13 -2
  20. package/dist/cjs/src/oracle/index.d.ts +4 -2
  21. package/dist/cjs/src/oracle/index.js +25 -6
  22. package/dist/cjs/src/oracle/price-update-rule.d.ts +3 -4
  23. package/dist/cjs/src/oracle/pyth.d.ts +68 -6
  24. package/dist/cjs/src/oracle/pyth.js +338 -22
  25. package/dist/cjs/src/oracle/rule-registry.d.ts +11 -6
  26. package/dist/cjs/src/oracle/rule-registry.js +13 -6
  27. package/dist/cjs/src/oracle/rules/pyth-core-rule.js +17 -2
  28. package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +6 -6
  29. package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +25 -22
  30. package/dist/cjs/src/oracle/rules/pyth-rule.js +5 -0
  31. package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +89 -0
  32. package/dist/cjs/src/oracle/rules/waterx-rule.js +272 -0
  33. package/dist/cjs/src/oracle/update-fetch.d.ts +32 -2
  34. package/dist/cjs/src/oracle/update-fetch.js +60 -3
  35. package/dist/cjs/src/perp/client.d.ts +71 -19
  36. package/dist/cjs/src/perp/client.js +30 -10
  37. package/dist/cjs/src/perp/config.d.ts +4 -7
  38. package/dist/cjs/src/perp/config.js +9 -12
  39. package/dist/cjs/src/perp/constants.d.ts +0 -6
  40. package/dist/cjs/src/perp/constants.js +11 -9
  41. package/dist/cjs/src/perp/fetch/account.js +3 -0
  42. package/dist/cjs/src/perp/fetch/bridge.js +2 -1
  43. package/dist/cjs/src/perp/fetch/market.js +2 -1
  44. package/dist/cjs/src/perp/fetch/positions.d.ts +16 -10
  45. package/dist/cjs/src/perp/fetch/positions.js +23 -20
  46. package/dist/cjs/src/perp/index.d.ts +8 -4
  47. package/dist/cjs/src/perp/index.js +12 -7
  48. package/dist/cjs/src/perp/liq-view.d.ts +64 -0
  49. package/dist/cjs/src/perp/liq-view.js +74 -0
  50. package/dist/cjs/src/perp/user/order.d.ts +13 -0
  51. package/dist/cjs/src/perp/user/order.js +30 -16
  52. package/dist/cjs/src/perp/user/staking.js +3 -2
  53. package/dist/cjs/src/perp/user/trading.js +25 -24
  54. package/dist/cjs/src/perp/user/wlp.js +6 -5
  55. package/dist/cjs/src/prediction/utils.d.ts +11 -2
  56. package/dist/cjs/src/prediction/utils.js +22 -22
  57. package/dist/cjs/src/unified-client.d.ts +49 -20
  58. package/dist/cjs/src/unified-client.js +4 -1
  59. package/dist/cjs/src/utils/format.d.ts +14 -0
  60. package/dist/cjs/src/utils/format.js +24 -0
  61. package/dist/cjs/src/utils/math.d.ts +304 -12
  62. package/dist/cjs/src/utils/math.js +397 -17
  63. package/dist/cjs/src/utils/validate.d.ts +69 -0
  64. package/dist/cjs/src/utils/validate.js +183 -0
  65. package/dist/src/account/account.js +2 -1
  66. package/dist/src/account/config.d.ts +0 -16
  67. package/dist/src/account/funding/balance.d.ts +25 -2
  68. package/dist/src/account/funding/balance.js +36 -24
  69. package/dist/src/account/funding/credit.js +6 -10
  70. package/dist/src/constants.d.ts +15 -1
  71. package/dist/src/constants.js +17 -3
  72. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  73. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +10 -0
  74. package/dist/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  75. package/dist/src/generated/waterx_rule/deps/sui/vec_map.js +27 -0
  76. package/dist/src/generated/waterx_rule/waterx_rule.d.ts +940 -0
  77. package/dist/src/generated/waterx_rule/waterx_rule.js +991 -0
  78. package/dist/src/oracle/aggregate.d.ts +21 -21
  79. package/dist/src/oracle/aggregate.js +84 -71
  80. package/dist/src/oracle/config.d.ts +107 -52
  81. package/dist/src/oracle/config.js +14 -34
  82. package/dist/src/oracle/host.d.ts +13 -2
  83. package/dist/src/oracle/index.d.ts +4 -2
  84. package/dist/src/oracle/index.js +18 -7
  85. package/dist/src/oracle/price-update-rule.d.ts +3 -4
  86. package/dist/src/oracle/pyth.d.ts +68 -6
  87. package/dist/src/oracle/pyth.js +334 -22
  88. package/dist/src/oracle/rule-registry.d.ts +11 -6
  89. package/dist/src/oracle/rule-registry.js +13 -6
  90. package/dist/src/oracle/rules/pyth-core-rule.js +18 -3
  91. package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +6 -6
  92. package/dist/src/oracle/rules/pyth-lazer-rule.js +26 -23
  93. package/dist/src/oracle/rules/pyth-rule.js +5 -0
  94. package/dist/src/oracle/rules/waterx-rule.d.ts +89 -0
  95. package/dist/src/oracle/rules/waterx-rule.js +266 -0
  96. package/dist/src/oracle/update-fetch.d.ts +32 -2
  97. package/dist/src/oracle/update-fetch.js +57 -3
  98. package/dist/src/perp/client.d.ts +71 -19
  99. package/dist/src/perp/client.js +31 -11
  100. package/dist/src/perp/config.d.ts +4 -7
  101. package/dist/src/perp/config.js +9 -12
  102. package/dist/src/perp/constants.d.ts +0 -6
  103. package/dist/src/perp/constants.js +10 -8
  104. package/dist/src/perp/fetch/account.js +3 -0
  105. package/dist/src/perp/fetch/bridge.js +2 -1
  106. package/dist/src/perp/fetch/market.js +2 -1
  107. package/dist/src/perp/fetch/positions.d.ts +16 -10
  108. package/dist/src/perp/fetch/positions.js +28 -20
  109. package/dist/src/perp/index.d.ts +8 -4
  110. package/dist/src/perp/index.js +5 -3
  111. package/dist/src/perp/liq-view.d.ts +64 -0
  112. package/dist/src/perp/liq-view.js +71 -0
  113. package/dist/src/perp/user/order.d.ts +13 -0
  114. package/dist/src/perp/user/order.js +30 -16
  115. package/dist/src/perp/user/staking.js +3 -2
  116. package/dist/src/perp/user/trading.js +25 -24
  117. package/dist/src/perp/user/wlp.js +6 -5
  118. package/dist/src/prediction/utils.d.ts +11 -2
  119. package/dist/src/prediction/utils.js +22 -22
  120. package/dist/src/unified-client.d.ts +49 -20
  121. package/dist/src/unified-client.js +4 -1
  122. package/dist/src/utils/format.d.ts +14 -0
  123. package/dist/src/utils/format.js +21 -0
  124. package/dist/src/utils/math.d.ts +304 -12
  125. package/dist/src/utils/math.js +394 -17
  126. package/dist/src/utils/validate.d.ts +69 -0
  127. package/dist/src/utils/validate.js +167 -0
  128. package/package.json +4 -1
package/README.md CHANGED
@@ -14,11 +14,12 @@ import { WaterXClient } from "@waterx/sdk";
14
14
  // waterxConfigUrl is REQUIRED — the SDK has no built-in default and never reads env.
15
15
  const client = await WaterXClient.create({
16
16
  network: "TESTNET",
17
- waterxConfigUrl: "https://raw.githubusercontent.com/WaterXProtocol/waterx-config/main/testnet.json",
17
+ waterxConfigUrl:
18
+ "https://raw.githubusercontent.com/WaterXProtocol/waterx-config/main/testnet.json",
18
19
  });
19
- client.account.createAccount(tx, { alias }); // shared waterx_account + funding (credit/custody)
20
- client.perp.buildPlaceOrderTx(params); // perpetuals
21
- client.predict.placeOrder(tx, params); // prediction markets
20
+ client.account.createAccount(tx, { alias }); // shared waterx_account + funding (credit/custody)
21
+ client.perp.buildPlaceOrderTx(params); // perpetuals
22
+ client.predict.placeOrder(tx, params); // prediction markets
22
23
  // client.perp / client.predict ARE the line clients — sign/execute on them directly:
23
24
  // await client.perp.signAndExecuteTransaction({ transaction: tx, signer })
24
25
  // each line can target a different network + URL:
@@ -29,11 +30,11 @@ client.predict.placeOrder(tx, params); // prediction markets
29
30
 
30
31
  Import surfaces:
31
32
 
32
- | Import | What |
33
- |--------|------|
34
- | `@waterx/sdk` | `WaterXClient` (umbrella) + `perp` / `prediction` namespaces. Perp's API is also re-exported flat here (**deprecated** — prefer `client.perp` or the `perp` namespace; removed next major). |
35
- | `@waterx/sdk/perp` | Perp line: `PerpClient`, builders, fetch, Pyth/Wormhole utils. |
36
- | `@waterx/sdk/prediction` | Prediction line: `PredictClient`, builders, fetch, utils. |
33
+ | Import | What |
34
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
35
+ | `@waterx/sdk` | `WaterXClient` (umbrella) + `perp` / `prediction` namespaces. Perp's API is also re-exported flat here (**deprecated** — prefer `client.perp` or the `perp` namespace; removed next major). |
36
+ | `@waterx/sdk/perp` | Perp line: `PerpClient`, builders, fetch, Pyth/Wormhole utils. |
37
+ | `@waterx/sdk/prediction` | Prediction line: `PredictClient`, builders, fetch, utils. |
37
38
 
38
39
  ## Install
39
40
 
@@ -99,41 +100,55 @@ const predict = await PredictClient.create("TESTNET", { waterxConfigUrl }); // o
99
100
 
100
101
  Read-only queries use gRPC `simulateTransaction` (no signer) — the `getX` view helpers, e.g. `await perp.simulate(tx)` or `getMarketData(perp, …)`.
101
102
 
102
- ## Oracle sources & the Pyth Pro migration
103
+ ## Oracle sources
104
+
105
+ ONE client create option, `oracleSource`, selects the price-update source. Each source is **self-contained** — it owns its own infra + config and does **not** back-stop any other source. The name is source-neutral on purpose: a future source need not be Pyth. The SDK **never reads `process.env`** — each consumer wires it from its own env var, so every environment runs the **same SDK version** and differs only by env:
103
106
 
104
- Two independent client create options control oracle behavior. The SDK **never reads `process.env`** — each consumer wires them from its own env vars, so every environment runs the **same SDK version** and differs only by env:
107
+ | Option | Values | What it selects |
108
+ | -------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
109
+ | `oracleSource` | `'pyth_rule'` (default) \| `'pyth_lazer_rule'` \| `'waterx_rule'` | The price-update source. `'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. |
105
110
 
106
- | Option | Values | What it flips |
107
- |--------|--------|---------------|
108
- | `oracleSource` | `'pyth_rule'` (default) \| `'pyth_lazer_rule'` | Which `PriceUpdateRule` `refreshOraclePrices` uses for the on-chain price-update leg. |
109
- | `pythGeneration` | `'core'` (default) \| `'pro'` | Which Pyth infra constants feed `client.pyth` when the config JSON has no explicit `pyth` block: `PYTH_DEFAULTS` (original contracts, keyless `hermes.pyth.network`) or `PYTH_PRO_DEFAULTS` (post-2026-08-18 Pro-compatible contracts + the Hermes-compatible `https://pyth.dourolabs.app/hermes`, auth-first). |
111
+ **No cross-source fallback, no init guard.** Selecting a source whose feed for a requested ticker is absent is **not** an error at client creation — it fails at **tx-build** for exactly those tickers (constant-only tickers, which need no price update, are exempt). A present-but-wrong feed id is not validated by the SDK; it aborts on-chain at dry-run.
110
112
 
111
- They are orthogonal: `pythGeneration` moves the Pyth **Core** state ids + endpoint; `oracleSource` picks the **rule** (Core VAA vs Lazer signed updates). An explicit `pyth` block in the config JSON always overrides the generation constants wholesale.
113
+ The Pyth Core infra (`client.pyth`: state ids + Hermes endpoint) is **fixed per network** by `PYTH_DEFAULTS` and is **not** deployment-overridable — the canonical `waterx-config` JSON carries no `pyth` block. The `pyth_lazer_rule` source reads only the credential/policy (`api_key`/`fetch`) from `client.pyth`; its on-chain infra comes from `LAZER_DEFAULTS` + config. The credential and fetch policy are passed at client init (`pythApiKey` / `pythFetch`), never through the JSON. `waterx_rule` touches no Pyth infra at all: its quote-center endpoint **defaults** to `WATERX_DEFAULTS[network]` (testnet `quote-center-staging.waterx.app` / mainnet `quote-center.waterx.app`) and is overridable with `waterxEndpoint`; its fetch policy/transport resolves **`waterxFetch` `pythFetch` → built-in defaults** (15s timeout, 2 retries), so the dedicated override wins and the shared Pyth policy is only the fallback. Both are client-init options — see the browser/CORS note below.
112
114
 
113
115
  ```ts
114
- // Per-environment wiring — the consumer owns the env vars, not the SDK:
116
+ // Per-environment wiring — the consumer owns the env var, not the SDK:
115
117
  const perp = await PerpClient.create(network, {
116
118
  waterxConfigUrl,
117
- oracleSource: process.env.ORACLE_SOURCE as OracleSource | undefined, // e.g. staging: pyth_lazer_rule
118
- pythGeneration: process.env.PYTH_GENERATION as PythGeneration | undefined, // e.g. staging: pro
119
+ oracleSource: process.env.ORACLE_SOURCE as OracleSource | undefined, // e.g. staging: 'pyth_lazer_rule' | 'waterx_rule'
120
+ pythApiKey: process.env.PYTH_API_KEY, // Lazer is auth-first; unused by 'pyth_rule' / 'waterx_rule'
119
121
  });
120
- // After the 2026-08-18 cutover, Pro-generation Hermes requires a key:
121
- perp.pyth = { ...perp.pyth, api_key: process.env.PYTH_API_KEY };
122
122
  ```
123
123
 
124
- This is the staging-Pro / prod-Core rollout pattern: staging sets `ORACLE_SOURCE=pyth_lazer_rule` and/or `PYTH_GENERATION=pro` while production leaves both unset (Core defaults) — flipping an environment is an env-var change, never an SDK release. After August 18, 2026 (the Core-upgrade cutover — see https://docs.pyth.network/price-feeds/core/upgrade), consumers set `pythGeneration: 'pro'` + `pyth.api_key`.
124
+ This is the staging-Lazer / prod-Core rollout pattern: staging sets `ORACLE_SOURCE=pyth_lazer_rule` (+ `PYTH_API_KEY`) — or `ORACLE_SOURCE=waterx_rule`, which needs no credential — while production leaves it unset — flipping an environment is an env-var change, never an SDK release.
125
125
 
126
126
  ### Adding an oracle source (runbook)
127
127
 
128
- Every rule generation plugs in the same way — routing is driven **only** by the client's `oracleSource` option (never a config `enabled` flag, never `process.env`):
128
+ Every source plugs in the same way — routing is driven **only** by the client's `oracleSource` option (never a config `enabled` flag, never `process.env`):
129
129
 
130
130
  1. **Implement `PriceUpdateRule`** in `src/oracle/rules/<name>-rule.ts` — all port fields (`src/oracle/price-update-rule.ts`): `kind`, `requiresFeeSource` (`true` iff the on-chain verify draws a per-update fee — gates the fail-fast fee-source check), `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), `buildUpdateCalls`.
131
131
  2. **Register it** in `src/oracle/rule-registry.ts` (`DEFAULT_RULES`) under a new `OracleSource` value (added to the union in `price-update-rule.ts`).
132
132
  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`).
133
- 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 per-network map in `src/oracle/config.ts`, mirroring `LAZER_DEFAULTS` / `PYTH_PRO_DEFAULTS`.
134
- 5. **Consumers flip `ORACLE_SOURCE`** per environment — no consumer code change, no SDK re-release.
135
-
136
- The in-house `waterx_rule` (ed25519 enclave-signed CEX prices) follows exactly this path when it lands.
133
+ 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 per-network map in `src/oracle/config.ts`, mirroring `LAZER_DEFAULTS` / `WATERX_DEFAULTS`.
134
+ 5. **Consumers flip `oracleSource`** per environment — no consumer code change, no SDK re-release.
135
+
136
+ The in-house `waterx_rule` (ed25519 enclave-signed CEX prices, `src/oracle/rules/waterx-rule.ts`) took exactly this path: it pulls one enclave-signed batch envelope covering the requested tickers from the quote-center (`GET /v1/quotes/update?symbols=…`, public read — no auth), then verifies **and** feeds in a single `waterx_rule::collect_batch_latest` call per collector, so it emits no shared verify step. On-chain a freshness miss / replayed timestamp abstains (the other weighted rules cover); a config mismatch or bad signature aborts.
137
+
138
+ > **Browser consumers:** this source fetches the quote-center directly from the page, so the quote-center deployment must return `Access-Control-Allow-Origin` for the app's origin. For an origin that is not on that allowlist, point the SDK at your own proxy instead of the default host — the endpoint and the transport are both overridable at client init:
139
+ >
140
+ > ```ts
141
+ > const perp = await PerpClient.create(network, {
142
+ > waterxConfigUrl,
143
+ > oracleSource: "waterx_rule",
144
+ > // absolute URL on your own origin; its base path is PRESERVED, so this
145
+ > // fetches https://app.example/api/quote-center/v1/quotes/update
146
+ > waterxEndpoint: "https://app.example/api/quote-center",
147
+ > waterxFetch: { fetchImpl: myFetch, timeoutMs: 8_000 }, // optional custom transport / policy
148
+ > });
149
+ > ```
150
+ >
151
+ > Unset, `waterxEndpoint` falls back to `WATERX_DEFAULTS[network]` and `waterxFetch` to `pythFetch`, then to the built-in policy (15s timeout, 2 retries). Both are inert under the Pyth sources. They are also top-level options on the umbrella `WaterXClient.create({ oracleSource, waterxEndpoint, waterxFetch, … })`, which forwards them to the perp line. Node/keeper consumers are unaffected by CORS either way.
137
152
 
138
153
  ## Recipes & full surface
139
154
 
@@ -143,18 +158,18 @@ To avoid doc drift, per-action usage lives in maintained, lint-checked code rath
143
158
  - **Prediction recipes:** [`test/prediction/e2e/`](./test/prediction/e2e) — the live reference for `client.predict.*` flows.
144
159
  - **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`.
145
160
 
146
- Perp `build*Tx` helpers are Pyth-backed (`async`; they refresh feeds before the call). Oracle (Pyth/Hermes) helpers live in [`src/oracle/`](./src/oracle).
161
+ Perp `build*Tx` helpers are oracle-backed (`async`; they refresh prices before the call) — through whichever source `oracleSource` selects, not Pyth specifically. The oracle layer (sources, rules, refresh) lives in [`src/oracle/`](./src/oracle).
147
162
 
148
163
  ## Development
149
164
 
150
- | Command | Use |
151
- | --- | --- |
152
- | `pnpm typecheck` | Typecheck the whole tree |
153
- | `pnpm test` / `pnpm test:unit` | Unit tests (perp + prediction) |
154
- | `pnpm test:e2e` | Testnet simulate e2e (perp + prediction) |
155
- | `pnpm test:integration` | On-chain integration (needs `SUI_PRIVATE_KEY`; local-only) |
156
- | `pnpm lint` / `pnpm format` | ESLint + Prettier |
157
- | `pnpm codegen` | Regenerate `src/generated` from Move |
158
- | `pnpm seed:testnet` | Seed prediction testnet fixtures (needs `SUI_PRIVATE_KEY`) |
165
+ | Command | Use |
166
+ | ------------------------------ | ---------------------------------------------------------- |
167
+ | `pnpm typecheck` | Typecheck the whole tree |
168
+ | `pnpm test` / `pnpm test:unit` | Unit tests (perp + prediction) |
169
+ | `pnpm test:e2e` | Testnet simulate e2e (perp + prediction) |
170
+ | `pnpm test:integration` | On-chain integration (needs `SUI_PRIVATE_KEY`; local-only) |
171
+ | `pnpm lint` / `pnpm format` | ESLint + Prettier |
172
+ | `pnpm codegen` | Regenerate `src/generated` from Move |
173
+ | `pnpm seed:testnet` | Seed prediction testnet fixtures (needs `SUI_PRIVATE_KEY`) |
159
174
 
160
175
  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.
@@ -57,6 +57,7 @@ exports.requestWithdraw = requestWithdraw;
57
57
  exports.transferToAccount = transferToAccount;
58
58
  exports.receive = receive;
59
59
  const wxa = __importStar(require("../generated/waterx_account/account.js"));
60
+ const validate_ts_1 = require("../utils/validate.js");
60
61
  const account_request_ts_1 = require("./account-request.js");
61
62
  const constants_ts_1 = require("./constants.js");
62
63
  const waterx_account_ts_1 = require("./waterx-account.js");
@@ -195,7 +196,7 @@ function requestWithdraw(client, tx, params) {
195
196
  registry: tx.object(client.config.packages.waterx_account.account_registry),
196
197
  senderRequest: req,
197
198
  accountId: params.accountId,
198
- amount: params.amount,
199
+ amount: (0, validate_ts_1.toU64)(params.amount, "amount"),
199
200
  recipient: params.recipient,
200
201
  extraData: Array.from(params.extraData ?? new Uint8Array()),
201
202
  },
@@ -48,28 +48,12 @@ export interface NativeCustodyPackage {
48
48
  /** Backing assets registered via `add_asset` (array, identified by `type`). */
49
49
  assets: NativeCustodyAsset[];
50
50
  }
51
- export interface TrustedEmitterRow {
52
- /** Source EVM chain's Wormhole chain id (e.g. 10002 = Sepolia). */
53
- chain_id: number;
54
- /** 32-byte left-padded EVM bridge address (0x form). */
55
- evm_bridge_address_32b: string;
56
- /** Whitelisted 20-byte EVM token addresses (0x form). */
57
- evm_tokens_20b: string[];
58
- }
59
51
  export interface WormholeBridgePackage {
60
52
  published_at: string;
61
53
  /** Shared Sui Wormhole `State` object id for this deployment. */
62
54
  wormhole_state: string;
63
- hourly_mint_limit?: string;
64
55
  max_mint_per_tx?: string;
65
- hourly_burn_limit?: string;
66
56
  max_burn_per_tx?: string;
67
- /**
68
- * @deprecated EVM emitter↔token config now lives solely under `evm.bridge.chains`
69
- * (deposit_vault = emitter, wormhole_chain_id = chain key). The runtime allowlist is
70
- * read from the on-chain `Bridge` object, not from config. Kept optional for back-compat.
71
- */
72
- trusted_emitters?: TrustedEmitterRow[];
73
57
  /** Shared `Bridge` (phase-5 output). */
74
58
  bridge?: string;
75
59
  /**
@@ -15,7 +15,15 @@ export interface ParkedBackingAssetBalance {
15
15
  /** Sum of `listCoins` object balances — TTO'd / owned `Coin<T>` path. */
16
16
  coinsRaw: bigint;
17
17
  }
18
- /** Rescale a u64 raw amount between token decimal precisions (truncates on downscale). */
18
+ /**
19
+ * Rescale a u64 raw amount between token decimal precisions (truncates on
20
+ * downscale). `toDecimals` defaults to {@link COLLATERAL_DECIMALS} — the
21
+ * CREDIT/wxUSD (collateral-typed) scale, 6 on every current deployment — for
22
+ * the common backing-asset → CREDIT direction. When rescaling a custody
23
+ * backing asset, always pass its per-asset config `decimal`
24
+ * (`NativeCustodyAsset.decimal`) as `fromDecimals`; never assume flat 6 — a
25
+ * 9-dec backing asset would otherwise mis-scale by 1000×.
26
+ */
19
27
  export declare function rescaleRawAmount(raw: bigint, fromDecimals: number, toDecimals?: number): bigint;
20
28
  /**
21
29
  * Probe every backing asset registered on `native_custody` for non-zero balances
@@ -26,7 +34,22 @@ export declare function probeParkedBackingAssets(client: AccountClientLike, acco
26
34
  /**
27
35
  * Probe non-zero CREDIT parked at `accountId`'s Sui address. Matches the
28
36
  * address-CREDIT legs inside {@link appendConsolidateAddressCredit}.
37
+ *
38
+ * RPC failures PROPAGATE (no swallow-to-zero): a gRPC error here used to be
39
+ * silently reported as an authoritative zero balance, which made
40
+ * `getSpendableCreditBalance` under-report spendable funds and let
41
+ * `appendConsolidateAddressCredit` build a tx that later aborted on-chain
42
+ * with a confusing insufficient-balance error. Callers that can tolerate a
43
+ * missing probe must catch explicitly.
29
44
  */
30
45
  export declare function probeAddressCreditBalance(client: AccountClientLike, accountId: string): Promise<AddressCreditBalance>;
31
- /** Sum parked backing assets into CREDIT base units at the 1:1 PSM peg. */
46
+ /**
47
+ * Sum parked backing assets into CREDIT base units at the 1:1 PSM peg.
48
+ * Each row rescales from its own per-asset `decimals` (sourced from config
49
+ * `NativeCustodyAsset.decimal` by {@link probeParkedBackingAssets}), so
50
+ * mixed-decimal backing sets (e.g. a 9-dec asset next to 6-dec USDC) sum
51
+ * correctly. `creditDecimals` is the CREDIT/wxUSD **target** scale —
52
+ * collateral-typed, 6 on all current deployments (the config JSON carries no
53
+ * credit decimal).
54
+ */
32
55
  export declare function sumParkedBackingAsCreditRaw(parked: readonly ParkedBackingAssetBalance[], creditDecimals?: number): bigint;
@@ -10,7 +10,15 @@ exports.sumParkedBackingAsCreditRaw = sumParkedBackingAsCreditRaw;
10
10
  * so display totals match what the next async tx-builder would sweep.
11
11
  */
12
12
  const constants_ts_1 = require("../../constants.js");
13
- /** Rescale a u64 raw amount between token decimal precisions (truncates on downscale). */
13
+ /**
14
+ * Rescale a u64 raw amount between token decimal precisions (truncates on
15
+ * downscale). `toDecimals` defaults to {@link COLLATERAL_DECIMALS} — the
16
+ * CREDIT/wxUSD (collateral-typed) scale, 6 on every current deployment — for
17
+ * the common backing-asset → CREDIT direction. When rescaling a custody
18
+ * backing asset, always pass its per-asset config `decimal`
19
+ * (`NativeCustodyAsset.decimal`) as `fromDecimals`; never assume flat 6 — a
20
+ * 9-dec backing asset would otherwise mis-scale by 1000×.
21
+ */
14
22
  function rescaleRawAmount(raw, fromDecimals, toDecimals = constants_ts_1.COLLATERAL_DECIMALS) {
15
23
  if (fromDecimals === toDecimals)
16
24
  return raw;
@@ -58,39 +66,43 @@ async function probeParkedBackingAssets(client, accountId) {
58
66
  /**
59
67
  * Probe non-zero CREDIT parked at `accountId`'s Sui address. Matches the
60
68
  * address-CREDIT legs inside {@link appendConsolidateAddressCredit}.
69
+ *
70
+ * RPC failures PROPAGATE (no swallow-to-zero): a gRPC error here used to be
71
+ * silently reported as an authoritative zero balance, which made
72
+ * `getSpendableCreditBalance` under-report spendable funds and let
73
+ * `appendConsolidateAddressCredit` build a tx that later aborted on-chain
74
+ * with a confusing insufficient-balance error. Callers that can tolerate a
75
+ * missing probe must catch explicitly.
61
76
  */
62
77
  async function probeAddressCreditBalance(client, accountId) {
63
78
  if (!client.config.packages.waterx_credit?.credit_type) {
64
79
  return { fundsRaw: 0n, coinsRaw: 0n };
65
80
  }
66
81
  const creditType = client.creditType();
67
- let fundsRaw = 0n;
82
+ const bal = (await client.getBalance({
83
+ owner: accountId,
84
+ coinType: creditType,
85
+ }));
86
+ const fundsRaw = BigInt(bal.balance?.addressBalance ?? "0");
87
+ const coins = (await client.listCoins({
88
+ owner: accountId,
89
+ coinType: creditType,
90
+ }));
68
91
  let coinsRaw = 0n;
69
- try {
70
- const bal = (await client.getBalance({
71
- owner: accountId,
72
- coinType: creditType,
73
- }));
74
- fundsRaw = BigInt(bal.balance?.addressBalance ?? "0");
75
- }
76
- catch {
77
- // ignore — treat as zero parked funds
78
- }
79
- try {
80
- const coins = (await client.listCoins({
81
- owner: accountId,
82
- coinType: creditType,
83
- }));
84
- for (const coin of coins.objects ?? []) {
85
- coinsRaw += BigInt(coin.balance ?? "0");
86
- }
87
- }
88
- catch {
89
- // ignore — treat as zero owned coins
92
+ for (const coin of coins.objects ?? []) {
93
+ coinsRaw += BigInt(coin.balance ?? "0");
90
94
  }
91
95
  return { fundsRaw, coinsRaw };
92
96
  }
93
- /** Sum parked backing assets into CREDIT base units at the 1:1 PSM peg. */
97
+ /**
98
+ * Sum parked backing assets into CREDIT base units at the 1:1 PSM peg.
99
+ * Each row rescales from its own per-asset `decimals` (sourced from config
100
+ * `NativeCustodyAsset.decimal` by {@link probeParkedBackingAssets}), so
101
+ * mixed-decimal backing sets (e.g. a 9-dec asset next to 6-dec USDC) sum
102
+ * correctly. `creditDecimals` is the CREDIT/wxUSD **target** scale —
103
+ * collateral-typed, 6 on all current deployments (the config JSON carries no
104
+ * credit decimal).
105
+ */
94
106
  function sumParkedBackingAsCreditRaw(parked, creditDecimals = constants_ts_1.COLLATERAL_DECIMALS) {
95
107
  let sum = 0n;
96
108
  for (const row of parked) {
@@ -35,6 +35,7 @@ const account_ts_1 = require("../../generated/waterx_account/account.js");
35
35
  const direct_rule_ts_1 = require("../../generated/waterx_account/direct_rule.js");
36
36
  const withdrawal_queue_ts_1 = require("../../generated/withdrawal_queue/withdrawal_queue.js");
37
37
  const wormhole_bridge_ts_1 = require("../../generated/wormhole_bridge/wormhole_bridge.js");
38
+ const validate_ts_1 = require("../../utils/validate.js");
38
39
  const account_request_ts_1 = require("../account-request.js");
39
40
  // ============================================================================
40
41
  // Byte helpers
@@ -137,15 +138,10 @@ function consumeCreditDeposit(client, tx, params) {
137
138
  }
138
139
  /** Build `withdrawal_queue::route_wormhole`. Returns the `extra_data` argument. */
139
140
  function routeWormhole(client, tx, params) {
140
- if (!Number.isInteger(params.evmDestinationChain) ||
141
- params.evmDestinationChain < 0 ||
142
- params.evmDestinationChain > 0xffff) {
143
- throw new Error(`evmDestinationChain must be a u16 (0..65535), got ${params.evmDestinationChain}`);
144
- }
145
141
  const out = (0, withdrawal_queue_ts_1.routeWormhole)({
146
142
  package: queuePkg(client),
147
143
  arguments: {
148
- evmDestinationChain: params.evmDestinationChain,
144
+ evmDestinationChain: (0, validate_ts_1.toU16)(params.evmDestinationChain, "evmDestinationChain"),
149
145
  evmRecipient: toEvmAddressBytes(params.evmRecipient, "evmRecipient"),
150
146
  evmToken: toEvmAddressBytes(params.evmToken, "evmToken"),
151
147
  },
@@ -156,7 +152,7 @@ function routeWormhole(client, tx, params) {
156
152
  function routeNative(client, tx, params) {
157
153
  const out = (0, withdrawal_queue_ts_1.routeNative)({
158
154
  package: queuePkg(client),
159
- arguments: { minOutput: BigInt(params.minOutput ?? 0n) },
155
+ arguments: { minOutput: (0, validate_ts_1.toU64)(params.minOutput ?? 0n, "minOutput") },
160
156
  typeArguments: [(0, utils_1.normalizeStructTag)(params.assetType)],
161
157
  })(tx);
162
158
  return out;
@@ -174,7 +170,7 @@ function requestCreditWithdraw(client, tx, params) {
174
170
  registry: tx.object(client.config.packages.waterx_account.account_registry),
175
171
  senderRequest: senderRequest,
176
172
  accountId: params.accountId,
177
- amount: params.amount,
173
+ amount: (0, validate_ts_1.toU64)(params.amount, "amount"),
178
174
  recipient: params.recipient,
179
175
  extraData: params.route,
180
176
  },
@@ -205,7 +201,7 @@ function executeWithdrawalWormhole(client, tx, params) {
205
201
  package: queuePkg(client),
206
202
  arguments: {
207
203
  queue: tx.object(queueId(client)),
208
- key: params.key,
204
+ key: (0, validate_ts_1.toU64)(params.key, "key"),
209
205
  request: request,
210
206
  bridge: tx.object(bridgeId(client)),
211
207
  creditRegistry: tx.object(creditRegistryId(client)),
@@ -222,7 +218,7 @@ function executeWithdrawalNative(client, tx, params) {
222
218
  package: queuePkg(client),
223
219
  arguments: {
224
220
  queue: tx.object(queueId(client)),
225
- key: params.key,
221
+ key: (0, validate_ts_1.toU64)(params.key, "key"),
226
222
  request: request,
227
223
  vault: tx.object(custodyVaultId(client)),
228
224
  creditRegistry: tx.object(creditRegistryId(client)),
@@ -9,7 +9,19 @@ export declare const DOUBLE_SCALE = 1000000000000000000n;
9
9
  export declare const SUI_DECIMALS = 9;
10
10
  /** WLP LP-token decimals. */
11
11
  export declare const WLP_DECIMALS = 6;
12
- /** Shared decimals for trading collateral / WLP backing assets (USDC, USDSUI). */
12
+ /**
13
+ * Decimals for **collateral-typed** values only: the CREDIT/wxUSD internal
14
+ * balance and the USD-pegged trading collateral (USDC, USDSUI). All current
15
+ * collateral and the CREDIT coin are 6-dec, and the config JSON carries no
16
+ * credit decimal, so this constant is the single source for the CREDIT scale.
17
+ *
18
+ * Do NOT use it for custody **backing assets** — those carry a per-asset
19
+ * `decimal` in config (`NativeCustodyAsset.decimal`), threaded through
20
+ * `probeParkedBackingAssets` → `sumParkedBackingAsCreditRaw`. If a 9-dec
21
+ * backing asset ever lists, a path that assumed flat 6 for it would mis-scale
22
+ * its parked balance by 1000×; only a change to the CREDIT coin itself (or a
23
+ * non-6-dec collateral listing) would require touching this constant.
24
+ */
13
25
  export declare const COLLATERAL_DECIMALS = 6;
14
26
  /**
15
27
  * @deprecated Import the individual `SUI_DECIMALS` / `WLP_DECIMALS` /
@@ -23,6 +35,8 @@ export declare const TOKEN_DECIMALS: {
23
35
  readonly USDSUI: 6;
24
36
  readonly WLP: 6;
25
37
  };
38
+ export declare const MS_PER_MINUTE: number;
39
+ export declare const MS_PER_HOUR: number;
26
40
  export declare const MS_PER_YEAR: number;
27
41
  /**
28
42
  * Zero-address placeholder used as the sender in dry-run / simulate calls.
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  // Shared, line-agnostic primitives (network id, scaling, decimals, time).
3
- // Perp-domain enums (permissions / order tags / action codes / fee rates) live
4
- // in `perp/constants.ts`; prediction has its own `prediction/constants.ts`.
3
+ // Perp-domain enums (permissions / order tags / action codes) live in
4
+ // `perp/constants.ts`; prediction has its own `prediction/constants.ts`.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DRY_RUN_SENDER = exports.MS_PER_YEAR = exports.TOKEN_DECIMALS = exports.COLLATERAL_DECIMALS = exports.WLP_DECIMALS = exports.SUI_DECIMALS = exports.DOUBLE_SCALE = exports.FLOAT_SCALE = exports.BPS_SCALE = void 0;
6
+ exports.DRY_RUN_SENDER = exports.MS_PER_YEAR = exports.MS_PER_HOUR = exports.MS_PER_MINUTE = exports.TOKEN_DECIMALS = exports.COLLATERAL_DECIMALS = exports.WLP_DECIMALS = exports.SUI_DECIMALS = exports.DOUBLE_SCALE = exports.FLOAT_SCALE = exports.BPS_SCALE = void 0;
7
7
  // ======== Scaling ========
8
8
  /** Basis-point denominator (10_000). Matches BP_SCALE in the Move contracts. */
9
9
  exports.BPS_SCALE = 10000n;
@@ -16,7 +16,19 @@ exports.DOUBLE_SCALE = 1000000000000000000n;
16
16
  exports.SUI_DECIMALS = 9;
17
17
  /** WLP LP-token decimals. */
18
18
  exports.WLP_DECIMALS = 6;
19
- /** Shared decimals for trading collateral / WLP backing assets (USDC, USDSUI). */
19
+ /**
20
+ * Decimals for **collateral-typed** values only: the CREDIT/wxUSD internal
21
+ * balance and the USD-pegged trading collateral (USDC, USDSUI). All current
22
+ * collateral and the CREDIT coin are 6-dec, and the config JSON carries no
23
+ * credit decimal, so this constant is the single source for the CREDIT scale.
24
+ *
25
+ * Do NOT use it for custody **backing assets** — those carry a per-asset
26
+ * `decimal` in config (`NativeCustodyAsset.decimal`), threaded through
27
+ * `probeParkedBackingAssets` → `sumParkedBackingAsCreditRaw`. If a 9-dec
28
+ * backing asset ever lists, a path that assumed flat 6 for it would mis-scale
29
+ * its parked balance by 1000×; only a change to the CREDIT coin itself (or a
30
+ * non-6-dec collateral listing) would require touching this constant.
31
+ */
20
32
  exports.COLLATERAL_DECIMALS = 6;
21
33
  /**
22
34
  * @deprecated Import the individual `SUI_DECIMALS` / `WLP_DECIMALS` /
@@ -31,6 +43,8 @@ exports.TOKEN_DECIMALS = {
31
43
  WLP: exports.WLP_DECIMALS,
32
44
  };
33
45
  // ======== Time ========
46
+ exports.MS_PER_MINUTE = 60 * 1000;
47
+ exports.MS_PER_HOUR = 60 * 60 * 1000;
34
48
  exports.MS_PER_YEAR = 365 * 24 * 60 * 60 * 1000;
35
49
  // ======== Well-known addresses ========
36
50
  /**
@@ -0,0 +1,8 @@
1
+ /**************************************************************
2
+ * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
3
+ **************************************************************/
4
+ /** Module for floating points */
5
+ import { MoveStruct } from '../../../utils/index.ts';
6
+ export declare const Float: MoveStruct<{
7
+ value: import("@mysten/sui/bcs").BcsType<string, string | number | bigint, "u128">;
8
+ }, "bucket_v2_framework::float::Float">;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**************************************************************
3
+ * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
4
+ **************************************************************/
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Float = void 0;
7
+ /** Module for floating points */
8
+ const index_ts_1 = require("../../../utils/index.js");
9
+ const bcs_1 = require("@mysten/sui/bcs");
10
+ const $moduleName = 'bucket_v2_framework::float';
11
+ exports.Float = new index_ts_1.MoveStruct({ name: `${$moduleName}::Float`, fields: {
12
+ value: bcs_1.bcs.u128()
13
+ } });
@@ -0,0 +1,36 @@
1
+ /**************************************************************
2
+ * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
3
+ **************************************************************/
4
+ import { type BcsType } from '@mysten/sui/bcs';
5
+ import { MoveStruct } from '../../../utils/index.ts';
6
+ /** An entry in the map */
7
+ export declare function Entry<K extends BcsType<any>, V extends BcsType<any>>(...typeParameters: [
8
+ K,
9
+ V
10
+ ]): MoveStruct<{
11
+ key: K;
12
+ value: V;
13
+ }, `0x2::vec_map::Entry<${K["name"]}, ${V["name"]}>`>;
14
+ /**
15
+ * A map data structure backed by a vector. The map is guaranteed not to contain
16
+ * duplicate keys, but entries are _not_ sorted by key--entries are included in
17
+ * insertion order. All operations are O(N) in the size of the map--the intention
18
+ * of this data structure is only to provide the convenience of programming against
19
+ * a map API. Large maps should use handwritten parent/child relationships instead.
20
+ * Maps that need sorted iteration rather than insertion order iteration should
21
+ * also be handwritten.
22
+ */
23
+ export declare function VecMap<K extends BcsType<any>, V extends BcsType<any>>(...typeParameters: [
24
+ K,
25
+ V
26
+ ]): MoveStruct<{
27
+ contents: BcsType<{
28
+ key: K extends BcsType<infer U, any, string> ? U : never;
29
+ value: V extends BcsType<infer U, any, string> ? U : never;
30
+ }[], Iterable<{
31
+ key: K extends BcsType<any, infer U_1, string> ? U_1 : never;
32
+ value: V extends BcsType<any, infer U_1, string> ? U_1 : never;
33
+ }> & {
34
+ length: number;
35
+ }, string>;
36
+ }, `0x2::vec_map::VecMap<${K["name"]}, ${V["name"]}>`>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Entry = Entry;
4
+ exports.VecMap = VecMap;
5
+ /**************************************************************
6
+ * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
7
+ **************************************************************/
8
+ const bcs_1 = require("@mysten/sui/bcs");
9
+ const index_ts_1 = require("../../../utils/index.js");
10
+ const $moduleName = '0x2::vec_map';
11
+ /** An entry in the map */
12
+ function Entry(...typeParameters) {
13
+ return new index_ts_1.MoveStruct({ name: `${$moduleName}::Entry<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
14
+ key: typeParameters[0],
15
+ value: typeParameters[1]
16
+ } });
17
+ }
18
+ /**
19
+ * A map data structure backed by a vector. The map is guaranteed not to contain
20
+ * duplicate keys, but entries are _not_ sorted by key--entries are included in
21
+ * insertion order. All operations are O(N) in the size of the map--the intention
22
+ * of this data structure is only to provide the convenience of programming against
23
+ * a map API. Large maps should use handwritten parent/child relationships instead.
24
+ * Maps that need sorted iteration rather than insertion order iteration should
25
+ * also be handwritten.
26
+ */
27
+ function VecMap(...typeParameters) {
28
+ return new index_ts_1.MoveStruct({ name: `${$moduleName}::VecMap<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
29
+ contents: bcs_1.bcs.vector(Entry(typeParameters[0], typeParameters[1]))
30
+ } });
31
+ }