@waterx/sdk 4.0.1 → 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 (110) hide show
  1. package/README.md +25 -10
  2. package/dist/cjs/src/account/account.js +2 -1
  3. package/dist/cjs/src/account/funding/balance.d.ts +25 -2
  4. package/dist/cjs/src/account/funding/balance.js +36 -24
  5. package/dist/cjs/src/account/funding/credit.js +6 -10
  6. package/dist/cjs/src/constants.d.ts +15 -1
  7. package/dist/cjs/src/constants.js +18 -4
  8. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  9. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +13 -0
  10. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  11. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.js +31 -0
  12. package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +940 -0
  13. package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +1092 -0
  14. package/dist/cjs/src/oracle/aggregate.d.ts +2 -0
  15. package/dist/cjs/src/oracle/aggregate.js +27 -2
  16. package/dist/cjs/src/oracle/config.d.ts +75 -0
  17. package/dist/cjs/src/oracle/config.js +15 -1
  18. package/dist/cjs/src/oracle/host.d.ts +12 -1
  19. package/dist/cjs/src/oracle/index.d.ts +2 -0
  20. package/dist/cjs/src/oracle/index.js +6 -1
  21. package/dist/cjs/src/oracle/price-update-rule.d.ts +3 -4
  22. package/dist/cjs/src/oracle/rule-registry.d.ts +8 -7
  23. package/dist/cjs/src/oracle/rule-registry.js +10 -7
  24. package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +89 -0
  25. package/dist/cjs/src/oracle/rules/waterx-rule.js +272 -0
  26. package/dist/cjs/src/perp/client.d.ts +44 -6
  27. package/dist/cjs/src/perp/client.js +14 -0
  28. package/dist/cjs/src/perp/config.d.ts +2 -3
  29. package/dist/cjs/src/perp/config.js +2 -1
  30. package/dist/cjs/src/perp/constants.d.ts +0 -6
  31. package/dist/cjs/src/perp/constants.js +11 -9
  32. package/dist/cjs/src/perp/fetch/account.js +3 -0
  33. package/dist/cjs/src/perp/fetch/bridge.js +2 -1
  34. package/dist/cjs/src/perp/fetch/market.js +2 -1
  35. package/dist/cjs/src/perp/fetch/positions.d.ts +16 -10
  36. package/dist/cjs/src/perp/fetch/positions.js +23 -20
  37. package/dist/cjs/src/perp/index.d.ts +6 -2
  38. package/dist/cjs/src/perp/index.js +12 -6
  39. package/dist/cjs/src/perp/liq-view.d.ts +64 -0
  40. package/dist/cjs/src/perp/liq-view.js +74 -0
  41. package/dist/cjs/src/perp/user/order.d.ts +13 -0
  42. package/dist/cjs/src/perp/user/order.js +30 -16
  43. package/dist/cjs/src/perp/user/staking.js +3 -2
  44. package/dist/cjs/src/perp/user/trading.js +25 -24
  45. package/dist/cjs/src/perp/user/wlp.js +6 -5
  46. package/dist/cjs/src/prediction/utils.d.ts +11 -2
  47. package/dist/cjs/src/prediction/utils.js +22 -22
  48. package/dist/cjs/src/unified-client.d.ts +31 -10
  49. package/dist/cjs/src/unified-client.js +2 -0
  50. package/dist/cjs/src/utils/format.d.ts +14 -0
  51. package/dist/cjs/src/utils/format.js +24 -0
  52. package/dist/cjs/src/utils/math.d.ts +304 -12
  53. package/dist/cjs/src/utils/math.js +397 -17
  54. package/dist/cjs/src/utils/validate.d.ts +69 -0
  55. package/dist/cjs/src/utils/validate.js +183 -0
  56. package/dist/src/account/account.js +2 -1
  57. package/dist/src/account/funding/balance.d.ts +25 -2
  58. package/dist/src/account/funding/balance.js +36 -24
  59. package/dist/src/account/funding/credit.js +6 -10
  60. package/dist/src/constants.d.ts +15 -1
  61. package/dist/src/constants.js +17 -3
  62. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  63. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +10 -0
  64. package/dist/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  65. package/dist/src/generated/waterx_rule/deps/sui/vec_map.js +27 -0
  66. package/dist/src/generated/waterx_rule/waterx_rule.d.ts +940 -0
  67. package/dist/src/generated/waterx_rule/waterx_rule.js +991 -0
  68. package/dist/src/oracle/aggregate.d.ts +2 -0
  69. package/dist/src/oracle/aggregate.js +27 -2
  70. package/dist/src/oracle/config.d.ts +75 -0
  71. package/dist/src/oracle/config.js +14 -0
  72. package/dist/src/oracle/host.d.ts +12 -1
  73. package/dist/src/oracle/index.d.ts +2 -0
  74. package/dist/src/oracle/index.js +3 -0
  75. package/dist/src/oracle/price-update-rule.d.ts +3 -4
  76. package/dist/src/oracle/rule-registry.d.ts +8 -7
  77. package/dist/src/oracle/rule-registry.js +10 -7
  78. package/dist/src/oracle/rules/waterx-rule.d.ts +89 -0
  79. package/dist/src/oracle/rules/waterx-rule.js +266 -0
  80. package/dist/src/perp/client.d.ts +44 -6
  81. package/dist/src/perp/client.js +15 -1
  82. package/dist/src/perp/config.d.ts +2 -3
  83. package/dist/src/perp/config.js +1 -1
  84. package/dist/src/perp/constants.d.ts +0 -6
  85. package/dist/src/perp/constants.js +10 -8
  86. package/dist/src/perp/fetch/account.js +3 -0
  87. package/dist/src/perp/fetch/bridge.js +2 -1
  88. package/dist/src/perp/fetch/market.js +2 -1
  89. package/dist/src/perp/fetch/positions.d.ts +16 -10
  90. package/dist/src/perp/fetch/positions.js +28 -20
  91. package/dist/src/perp/index.d.ts +6 -2
  92. package/dist/src/perp/index.js +4 -2
  93. package/dist/src/perp/liq-view.d.ts +64 -0
  94. package/dist/src/perp/liq-view.js +71 -0
  95. package/dist/src/perp/user/order.d.ts +13 -0
  96. package/dist/src/perp/user/order.js +30 -16
  97. package/dist/src/perp/user/staking.js +3 -2
  98. package/dist/src/perp/user/trading.js +25 -24
  99. package/dist/src/perp/user/wlp.js +6 -5
  100. package/dist/src/prediction/utils.d.ts +11 -2
  101. package/dist/src/prediction/utils.js +22 -22
  102. package/dist/src/unified-client.d.ts +31 -10
  103. package/dist/src/unified-client.js +2 -0
  104. package/dist/src/utils/format.d.ts +14 -0
  105. package/dist/src/utils/format.js +21 -0
  106. package/dist/src/utils/math.d.ts +304 -12
  107. package/dist/src/utils/math.js +394 -17
  108. package/dist/src/utils/validate.d.ts +69 -0
  109. package/dist/src/utils/validate.js +167 -0
  110. package/package.json +4 -1
package/README.md CHANGED
@@ -104,24 +104,24 @@ Read-only queries use gRPC `simulateTransaction` (no signer) — the `getX` view
104
104
 
105
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:
106
106
 
107
- | Option | Values | What it selects |
108
- | -------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
109
- | `oracleSource` | `'pyth_rule'` (default) \| `'pyth_lazer_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`. |
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. |
110
110
 
111
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.
112
112
 
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.
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.
114
114
 
115
115
  ```ts
116
116
  // Per-environment wiring — the consumer owns the env var, not the SDK:
117
117
  const perp = await PerpClient.create(network, {
118
118
  waterxConfigUrl,
119
- oracleSource: process.env.ORACLE_SOURCE as OracleSource | undefined, // e.g. staging: 'pyth_lazer_rule'
120
- pythApiKey: process.env.PYTH_API_KEY, // Lazer is auth-first; unused by 'pyth_rule'
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'
121
121
  });
122
122
  ```
123
123
 
124
- This is the staging-Lazer / prod-Core rollout pattern: staging sets `ORACLE_SOURCE=pyth_lazer_rule` (+ `PYTH_API_KEY`) while production leaves it unset — flipping an environment is an env-var change, never an SDK release.
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
 
@@ -130,10 +130,25 @@ Every source plugs in the same way — routing is driven **only** by the client'
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`.
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
134
  5. **Consumers flip `oracleSource`** per environment — no consumer code change, no SDK re-release.
135
135
 
136
- The in-house `waterx_rule` (ed25519 enclave-signed CEX prices) follows exactly this path when it lands.
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,7 +158,7 @@ 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
 
@@ -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
  },
@@ -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
+ }