@waterx/sdk 4.0.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +37 -17
  2. package/dist/cjs/src/account/account.js +2 -1
  3. package/dist/cjs/src/account/config.d.ts +3 -2
  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 +813 -0
  14. package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +946 -0
  15. package/dist/cjs/src/oracle/aggregate.d.ts +23 -21
  16. package/dist/cjs/src/oracle/aggregate.js +133 -59
  17. package/dist/cjs/src/oracle/config.d.ts +82 -41
  18. package/dist/cjs/src/oracle/config.js +0 -42
  19. package/dist/cjs/src/oracle/host.d.ts +26 -11
  20. package/dist/cjs/src/oracle/index.d.ts +6 -2
  21. package/dist/cjs/src/oracle/index.js +36 -8
  22. package/dist/cjs/src/oracle/price-update-rule.d.ts +16 -10
  23. package/dist/cjs/src/oracle/price-update-rule.js +3 -3
  24. package/dist/cjs/src/oracle/pyth.d.ts +44 -0
  25. package/dist/cjs/src/oracle/pyth.js +48 -6
  26. package/dist/cjs/src/oracle/read-plane.d.ts +70 -0
  27. package/dist/cjs/src/oracle/read-plane.js +78 -0
  28. package/dist/cjs/src/oracle/rule-registry.d.ts +14 -11
  29. package/dist/cjs/src/oracle/rule-registry.js +16 -11
  30. package/dist/cjs/src/oracle/rules/pyth-core-rule.js +4 -4
  31. package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
  32. package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +29 -4
  33. package/dist/cjs/src/oracle/rules/pyth-rule.js +5 -4
  34. package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +126 -0
  35. package/dist/cjs/src/oracle/rules/waterx-rule.js +312 -0
  36. package/dist/cjs/src/perp/client.d.ts +71 -20
  37. package/dist/cjs/src/perp/client.js +35 -13
  38. package/dist/cjs/src/perp/config.d.ts +6 -7
  39. package/dist/cjs/src/perp/config.js +12 -11
  40. package/dist/cjs/src/perp/constants.d.ts +0 -6
  41. package/dist/cjs/src/perp/constants.js +11 -9
  42. package/dist/cjs/src/perp/fetch/account.js +3 -0
  43. package/dist/cjs/src/perp/fetch/bridge.js +2 -1
  44. package/dist/cjs/src/perp/fetch/market.js +2 -1
  45. package/dist/cjs/src/perp/fetch/positions.d.ts +16 -10
  46. package/dist/cjs/src/perp/fetch/positions.js +23 -20
  47. package/dist/cjs/src/perp/index.d.ts +9 -5
  48. package/dist/cjs/src/perp/index.js +16 -7
  49. package/dist/cjs/src/perp/liq-view.d.ts +64 -0
  50. package/dist/cjs/src/perp/liq-view.js +74 -0
  51. package/dist/cjs/src/perp/user/order.d.ts +13 -0
  52. package/dist/cjs/src/perp/user/order.js +30 -16
  53. package/dist/cjs/src/perp/user/staking.js +3 -2
  54. package/dist/cjs/src/perp/user/trading.js +25 -24
  55. package/dist/cjs/src/perp/user/wlp.js +6 -5
  56. package/dist/cjs/src/prediction/utils.d.ts +11 -2
  57. package/dist/cjs/src/prediction/utils.js +22 -22
  58. package/dist/cjs/src/unified-client.d.ts +41 -15
  59. package/dist/cjs/src/unified-client.js +4 -2
  60. package/dist/cjs/src/utils/format.d.ts +14 -0
  61. package/dist/cjs/src/utils/format.js +24 -0
  62. package/dist/cjs/src/utils/math.d.ts +304 -12
  63. package/dist/cjs/src/utils/math.js +397 -17
  64. package/dist/cjs/src/utils/validate.d.ts +69 -0
  65. package/dist/cjs/src/utils/validate.js +183 -0
  66. package/dist/src/account/account.js +2 -1
  67. package/dist/src/account/config.d.ts +3 -2
  68. package/dist/src/account/funding/balance.d.ts +25 -2
  69. package/dist/src/account/funding/balance.js +36 -24
  70. package/dist/src/account/funding/credit.js +6 -10
  71. package/dist/src/constants.d.ts +15 -1
  72. package/dist/src/constants.js +17 -3
  73. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  74. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +10 -0
  75. package/dist/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  76. package/dist/src/generated/waterx_rule/deps/sui/vec_map.js +27 -0
  77. package/dist/src/generated/waterx_rule/waterx_rule.d.ts +813 -0
  78. package/dist/src/generated/waterx_rule/waterx_rule.js +855 -0
  79. package/dist/src/oracle/aggregate.d.ts +23 -21
  80. package/dist/src/oracle/aggregate.js +133 -59
  81. package/dist/src/oracle/config.d.ts +82 -41
  82. package/dist/src/oracle/config.js +1 -41
  83. package/dist/src/oracle/host.d.ts +26 -11
  84. package/dist/src/oracle/index.d.ts +6 -2
  85. package/dist/src/oracle/index.js +27 -9
  86. package/dist/src/oracle/price-update-rule.d.ts +16 -10
  87. package/dist/src/oracle/price-update-rule.js +3 -3
  88. package/dist/src/oracle/pyth.d.ts +44 -0
  89. package/dist/src/oracle/pyth.js +45 -5
  90. package/dist/src/oracle/read-plane.d.ts +70 -0
  91. package/dist/src/oracle/read-plane.js +74 -0
  92. package/dist/src/oracle/rule-registry.d.ts +14 -11
  93. package/dist/src/oracle/rule-registry.js +16 -11
  94. package/dist/src/oracle/rules/pyth-core-rule.js +5 -5
  95. package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
  96. package/dist/src/oracle/rules/pyth-lazer-rule.js +28 -3
  97. package/dist/src/oracle/rules/pyth-rule.js +5 -4
  98. package/dist/src/oracle/rules/waterx-rule.d.ts +126 -0
  99. package/dist/src/oracle/rules/waterx-rule.js +305 -0
  100. package/dist/src/perp/client.d.ts +71 -20
  101. package/dist/src/perp/client.js +36 -14
  102. package/dist/src/perp/config.d.ts +6 -7
  103. package/dist/src/perp/config.js +11 -9
  104. package/dist/src/perp/constants.d.ts +0 -6
  105. package/dist/src/perp/constants.js +10 -8
  106. package/dist/src/perp/fetch/account.js +3 -0
  107. package/dist/src/perp/fetch/bridge.js +2 -1
  108. package/dist/src/perp/fetch/market.js +2 -1
  109. package/dist/src/perp/fetch/positions.d.ts +16 -10
  110. package/dist/src/perp/fetch/positions.js +28 -20
  111. package/dist/src/perp/index.d.ts +9 -5
  112. package/dist/src/perp/index.js +6 -4
  113. package/dist/src/perp/liq-view.d.ts +64 -0
  114. package/dist/src/perp/liq-view.js +71 -0
  115. package/dist/src/perp/user/order.d.ts +13 -0
  116. package/dist/src/perp/user/order.js +30 -16
  117. package/dist/src/perp/user/staking.js +3 -2
  118. package/dist/src/perp/user/trading.js +25 -24
  119. package/dist/src/perp/user/wlp.js +6 -5
  120. package/dist/src/prediction/utils.d.ts +11 -2
  121. package/dist/src/prediction/utils.js +22 -22
  122. package/dist/src/unified-client.d.ts +41 -15
  123. package/dist/src/unified-client.js +4 -2
  124. package/dist/src/utils/format.d.ts +14 -0
  125. package/dist/src/utils/format.js +21 -0
  126. package/dist/src/utils/math.d.ts +304 -12
  127. package/dist/src/utils/math.js +394 -17
  128. package/dist/src/utils/validate.d.ts +69 -0
  129. package/dist/src/utils/validate.js +167 -0
  130. package/package.json +4 -1
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ // Numeric-domain guards. One place for the question "is this value inside the
3
+ // domain the callee can honestly compute over?", asked at the three points
4
+ // where garbage enters:
5
+ //
6
+ // 1. INTEGER params (`toU64` / `toU128` / `toU8` / `toU16` + the `*OrNull` /
7
+ // `toU64Arg` variants) on the fetch AND write (tx-build) surfaces. What the
8
+ // generated BCS layer does with a bad `number` depends on the width, and at
9
+ // no width is the answer "throw naming the parameter" (verified against
10
+ // `@mysten/sui`'s `bcs`):
11
+ // - u64 / u128 throw on negative and on fractional — but a `number` past
12
+ // 2^53 has already lost precision in JS BEFORE BCS sees it. `2**53 + 1`
13
+ // collapses to `2**53` at parse time, so BCS faithfully encodes a value
14
+ // the caller never wrote. (`2**53 + 2` IS exactly representable and
15
+ // encodes correctly — the hazard is the odd side of the f64 cliff, not
16
+ // BCS.) Hence the `Number.isSafeInteger` floor here.
17
+ // - u8 / u16 throw when the value is out of range but SILENTLY TRUNCATE a
18
+ // fractional one (`bcs.u8().serialize(2.7)` encodes `2`), so the
19
+ // fractional case is the one only a guard can catch.
20
+ // Every integer param funnels through these so garbage throws with the
21
+ // parameter's name before a transaction is built.
22
+ // 2. FLOAT / BIGINT domains (`assertFinite` / `assertFiniteNonNegative` /
23
+ // `assertUnitFraction` / `assertTokenDecimal` / `assertUnsignedBigInt`) for
24
+ // the money-path math in `utils/math.ts`.
25
+ // 3. The WHOLE-DOLLAR USD price domain (`WholeDollarUsdPrice` /
26
+ // `parseWholeDollarU64`) the `waterx_perp_view` read params live in.
27
+ //
28
+ // Families 2 and 3 live HERE rather than privately inside `math.ts` /
29
+ // `perp/fetch/positions.ts` so the whole numeric-domain vocabulary is
30
+ // discoverable in one file: hiding it is why `parseWholeDollarU64` once
31
+ // re-derived `toU64`'s entire chain (finite → integer → safe integer →
32
+ // non-negative → <= u64::MAX) by hand.
33
+ //
34
+ // Everything throws `RangeError` naming the offending parameter.
35
+ //
36
+ // Visibility: this module is internal EXCEPT for the whole-dollar pair, which
37
+ // is public and re-exported from `perp/fetch/positions.ts` (→ the `perp/fetch`
38
+ // barrel → `@waterx/sdk`) — that is the published import path, not this file.
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.U64_MAX = void 0;
41
+ exports.toU64 = toU64;
42
+ exports.toU128 = toU128;
43
+ exports.toU8 = toU8;
44
+ exports.toU16 = toU16;
45
+ exports.toU64OrNull = toU64OrNull;
46
+ exports.toU128OrNull = toU128OrNull;
47
+ exports.toU64Arg = toU64Arg;
48
+ exports.assertFinite = assertFinite;
49
+ exports.assertFiniteNonNegative = assertFiniteNonNegative;
50
+ exports.assertUnitFraction = assertUnitFraction;
51
+ exports.assertTokenDecimal = assertTokenDecimal;
52
+ exports.assertUnsignedBigInt = assertUnsignedBigInt;
53
+ exports.parseWholeDollarU64 = parseWholeDollarU64;
54
+ exports.U64_MAX = 18446744073709551615n; // 2^64 − 1
55
+ const U128_MAX = 340282366920938463463374607431768211455n; // 2^128 − 1
56
+ function toUint(value, label, max, width) {
57
+ let v;
58
+ if (typeof value === "bigint") {
59
+ v = value;
60
+ }
61
+ else {
62
+ if (!Number.isSafeInteger(value) || value < 0) {
63
+ throw new RangeError(`${label} must be a non-negative safe integer (< 2^53) or a bigint, got ${value}`);
64
+ }
65
+ v = BigInt(value);
66
+ }
67
+ if (v < 0n || v > max) {
68
+ throw new RangeError(`${label} out of ${width} range, got ${v}`);
69
+ }
70
+ return v;
71
+ }
72
+ /** Validate a u64 param (bigint passthrough with range check; number must be a safe integer >= 0). */
73
+ function toU64(value, label) {
74
+ return toUint(value, label, exports.U64_MAX, "u64");
75
+ }
76
+ /** Validate a u128 param (bigint passthrough with range check; number must be a safe integer >= 0). */
77
+ function toU128(value, label) {
78
+ return toUint(value, label, U128_MAX, "u128");
79
+ }
80
+ function toSmallUint(value, label, max, width) {
81
+ if (!Number.isInteger(value) || value < 0 || value > max) {
82
+ throw new RangeError(`${label} must be an integer in [0, ${max}] (${width}), got ${value}`);
83
+ }
84
+ return value;
85
+ }
86
+ /**
87
+ * Validate a u8 param. Returns a `number` (not a bigint) because that is the
88
+ * shape the generated BCS layer takes at this width.
89
+ *
90
+ * Separate from `toU64` on purpose: at u8/u16 the BCS writer already throws on
91
+ * an out-of-range value, but SILENTLY TRUNCATES a fractional one — so the
92
+ * fractional case is what this guard exists to catch (see the header note).
93
+ */
94
+ function toU8(value, label) {
95
+ return toSmallUint(value, label, 0xff, "u8");
96
+ }
97
+ /** Validate a u16 param. Same width caveat as {@link toU8}. */
98
+ function toU16(value, label) {
99
+ return toSmallUint(value, label, 0xffff, "u16");
100
+ }
101
+ /** `Option<u64>` param: `null` / `undefined` pass through as `null`, anything else is validated. */
102
+ function toU64OrNull(value, label) {
103
+ return value == null ? null : toU64(value, label);
104
+ }
105
+ /** `Option<u128>` param: `null` / `undefined` pass through as `null`, anything else is validated. */
106
+ function toU128OrNull(value, label) {
107
+ return value == null ? null : toU128(value, label);
108
+ }
109
+ /**
110
+ * u64 param that may instead be a PTB result chained from an earlier command
111
+ * (e.g. the `lp_amount` returned by `mintWlp`). A `TransactionArgument` passes
112
+ * through untouched — its value only exists on chain, where Move types it.
113
+ */
114
+ function toU64Arg(value, label) {
115
+ return typeof value === "bigint" || typeof value === "number" ? toU64(value, label) : value;
116
+ }
117
+ // NOTE: there is deliberately no `toU128Arg`. No write builder exposes a u128
118
+ // param that can take a chained `TransactionArgument` (every u128 site — size /
119
+ // trigger price / acceptable price — is a caller-supplied literal), so a u128
120
+ // half of `toU64Arg` would be an export with no consumer. Add it back the day a
121
+ // builder actually chains a u128 PTB result.
122
+ /** Reject NaN / ±Infinity for a `number` money-path input. */
123
+ function assertFinite(label, value) {
124
+ if (!Number.isFinite(value)) {
125
+ throw new RangeError(`${label} must be a finite number, got ${value}`);
126
+ }
127
+ }
128
+ /** Reject NaN / ±Infinity / negative for a `number` money-path input. */
129
+ function assertFiniteNonNegative(label, value) {
130
+ assertFinite(label, value);
131
+ if (value < 0) {
132
+ throw new RangeError(`${label} must be >= 0, got ${value}`);
133
+ }
134
+ }
135
+ /**
136
+ * Reject anything outside `[0, 1]` for a `number` input that is a FRACTION of a
137
+ * whole — a maintenance-margin rate above 1 means "maintenance exceeds the
138
+ * entire notional", which is not a rate the caller can have meant.
139
+ */
140
+ function assertUnitFraction(label, value) {
141
+ assertFinite(label, value);
142
+ if (value < 0 || value > 1) {
143
+ throw new RangeError(`${label} must be within [0, 1], got ${value}`);
144
+ }
145
+ }
146
+ /**
147
+ * Reject a token-decimal outside `[0, 19]` — the domain of the contract's
148
+ * `10u64.pow(decimal)` (`10^19 < 2^64 <= 10^20`), and the same bound the raw
149
+ * `POW10` table in `utils/math.ts` is built over.
150
+ */
151
+ function assertTokenDecimal(label, value) {
152
+ if (!Number.isInteger(value) || value < 0 || value > 19) {
153
+ throw new RangeError(`${label} must be an integer in [0, 19], got ${value}`);
154
+ }
155
+ }
156
+ /** Reject a negative `bigint` where the on-chain type is unsigned. */
157
+ function assertUnsignedBigInt(label, value) {
158
+ if (value < 0n) {
159
+ throw new RangeError(`${label} must be >= 0, got ${value}`);
160
+ }
161
+ }
162
+ const PLAIN_INT_RE = /^-?\d+$/;
163
+ /**
164
+ * Parse a user/env-supplied value into a whole-dollar u64 price
165
+ * (`WholeDollarUsdPrice`) with NO silent rounding: throws `RangeError` on
166
+ * fractional, negative, non-finite, non-numeric, or `> u64::MAX` input. If
167
+ * rounding is ever wanted it must be explicit at the call site
168
+ * (e.g. `parseWholeDollarU64(Math.round(x))`) — never baked in here.
169
+ *
170
+ * The numeric domain (finite → safe integer → non-negative → `<= u64::MAX`) is
171
+ * `toU64`'s and is NOT restated here; this function only adds the string form,
172
+ * whose digits parse exactly past the 2^53 f64 cliff.
173
+ */
174
+ function parseWholeDollarU64(value) {
175
+ const label = "whole-dollar USD price";
176
+ if (typeof value !== "string")
177
+ return toU64(value, label);
178
+ const trimmed = value.trim();
179
+ if (!PLAIN_INT_RE.test(trimmed)) {
180
+ throw new RangeError(`${label} must be a plain integer string, got "${value}"`);
181
+ }
182
+ return toU64(BigInt(trimmed), label);
183
+ }
@@ -11,6 +11,7 @@
11
11
  * or a `TransactionArgument`).
12
12
  */
13
13
  import * as wxa from "../generated/waterx_account/account.js";
14
+ import { toU64 } from "../utils/validate.js";
14
15
  import { makeSenderRequest } from "./account-request.js";
15
16
  import { ACCUMULATOR_ROOT } from "./constants.js";
16
17
  import { createAccountCall } from "./waterx-account.js";
@@ -149,7 +150,7 @@ export function requestWithdraw(client, tx, params) {
149
150
  registry: tx.object(client.config.packages.waterx_account.account_registry),
150
151
  senderRequest: req,
151
152
  accountId: params.accountId,
152
- amount: params.amount,
153
+ amount: toU64(params.amount, "amount"),
153
154
  recipient: params.recipient,
154
155
  extraData: Array.from(params.extraData ?? new Uint8Array()),
155
156
  },
@@ -73,8 +73,9 @@ export interface WithdrawalQueuePackage {
73
73
  /**
74
74
  * Wormhole infra for the cross-chain credit bridge. `state_id` is the same
75
75
  * shared Sui Wormhole `State` object Pyth uses (kept in sync with
76
- * `PYTH_DEFAULTS[*].wormhole_state_id`). Override per-deployment via
77
- * `WaterXConfig.wormhole` if a deployment ever points elsewhere.
76
+ * `PYTH_CORE_INFRA[*].wormhole_state_id` in `oracle/pyth.ts`). Override
77
+ * per-deployment via `WaterXConfig.wormhole` if a deployment ever points
78
+ * elsewhere.
78
79
  */
79
80
  export interface WormholeInfraConfig {
80
81
  /** Shared Sui Wormhole `State` object. */
@@ -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;
@@ -4,7 +4,15 @@
4
4
  * so display totals match what the next async tx-builder would sweep.
5
5
  */
6
6
  import { COLLATERAL_DECIMALS } from "../../constants.js";
7
- /** Rescale a u64 raw amount between token decimal precisions (truncates on downscale). */
7
+ /**
8
+ * Rescale a u64 raw amount between token decimal precisions (truncates on
9
+ * downscale). `toDecimals` defaults to {@link COLLATERAL_DECIMALS} — the
10
+ * CREDIT/wxUSD (collateral-typed) scale, 6 on every current deployment — for
11
+ * the common backing-asset → CREDIT direction. When rescaling a custody
12
+ * backing asset, always pass its per-asset config `decimal`
13
+ * (`NativeCustodyAsset.decimal`) as `fromDecimals`; never assume flat 6 — a
14
+ * 9-dec backing asset would otherwise mis-scale by 1000×.
15
+ */
8
16
  export function rescaleRawAmount(raw, fromDecimals, toDecimals = COLLATERAL_DECIMALS) {
9
17
  if (fromDecimals === toDecimals)
10
18
  return raw;
@@ -52,39 +60,43 @@ export async function probeParkedBackingAssets(client, accountId) {
52
60
  /**
53
61
  * Probe non-zero CREDIT parked at `accountId`'s Sui address. Matches the
54
62
  * address-CREDIT legs inside {@link appendConsolidateAddressCredit}.
63
+ *
64
+ * RPC failures PROPAGATE (no swallow-to-zero): a gRPC error here used to be
65
+ * silently reported as an authoritative zero balance, which made
66
+ * `getSpendableCreditBalance` under-report spendable funds and let
67
+ * `appendConsolidateAddressCredit` build a tx that later aborted on-chain
68
+ * with a confusing insufficient-balance error. Callers that can tolerate a
69
+ * missing probe must catch explicitly.
55
70
  */
56
71
  export async function probeAddressCreditBalance(client, accountId) {
57
72
  if (!client.config.packages.waterx_credit?.credit_type) {
58
73
  return { fundsRaw: 0n, coinsRaw: 0n };
59
74
  }
60
75
  const creditType = client.creditType();
61
- let fundsRaw = 0n;
76
+ const bal = (await client.getBalance({
77
+ owner: accountId,
78
+ coinType: creditType,
79
+ }));
80
+ const fundsRaw = BigInt(bal.balance?.addressBalance ?? "0");
81
+ const coins = (await client.listCoins({
82
+ owner: accountId,
83
+ coinType: creditType,
84
+ }));
62
85
  let coinsRaw = 0n;
63
- try {
64
- const bal = (await client.getBalance({
65
- owner: accountId,
66
- coinType: creditType,
67
- }));
68
- fundsRaw = BigInt(bal.balance?.addressBalance ?? "0");
69
- }
70
- catch {
71
- // ignore — treat as zero parked funds
72
- }
73
- try {
74
- const coins = (await client.listCoins({
75
- owner: accountId,
76
- coinType: creditType,
77
- }));
78
- for (const coin of coins.objects ?? []) {
79
- coinsRaw += BigInt(coin.balance ?? "0");
80
- }
81
- }
82
- catch {
83
- // ignore — treat as zero owned coins
86
+ for (const coin of coins.objects ?? []) {
87
+ coinsRaw += BigInt(coin.balance ?? "0");
84
88
  }
85
89
  return { fundsRaw, coinsRaw };
86
90
  }
87
- /** Sum parked backing assets into CREDIT base units at the 1:1 PSM peg. */
91
+ /**
92
+ * Sum parked backing assets into CREDIT base units at the 1:1 PSM peg.
93
+ * Each row rescales from its own per-asset `decimals` (sourced from config
94
+ * `NativeCustodyAsset.decimal` by {@link probeParkedBackingAssets}), so
95
+ * mixed-decimal backing sets (e.g. a 9-dec asset next to 6-dec USDC) sum
96
+ * correctly. `creditDecimals` is the CREDIT/wxUSD **target** scale —
97
+ * collateral-typed, 6 on all current deployments (the config JSON carries no
98
+ * credit decimal).
99
+ */
88
100
  export function sumParkedBackingAsCreditRaw(parked, creditDecimals = COLLATERAL_DECIMALS) {
89
101
  let sum = 0n;
90
102
  for (const row of parked) {
@@ -24,6 +24,7 @@ import { requestWithdraw as requestWithdrawCall } from "../../generated/waterx_a
24
24
  import { consumeDepositDirect } from "../../generated/waterx_account/direct_rule.js";
25
25
  import { enqueue as enqueueCall, executeNative as executeNativeCall, executeWormhole as executeWormholeCall, routeNative as routeNativeCall, routeWormhole as routeWormholeCall, } from "../../generated/withdrawal_queue/withdrawal_queue.js";
26
26
  import { redeemVaa as redeemVaaCall } from "../../generated/wormhole_bridge/wormhole_bridge.js";
27
+ import { toU16, toU64 } from "../../utils/validate.js";
27
28
  import { makeSenderRequest } from "../account-request.js";
28
29
  // ============================================================================
29
30
  // Byte helpers
@@ -126,15 +127,10 @@ export function consumeCreditDeposit(client, tx, params) {
126
127
  }
127
128
  /** Build `withdrawal_queue::route_wormhole`. Returns the `extra_data` argument. */
128
129
  export function routeWormhole(client, tx, params) {
129
- if (!Number.isInteger(params.evmDestinationChain) ||
130
- params.evmDestinationChain < 0 ||
131
- params.evmDestinationChain > 0xffff) {
132
- throw new Error(`evmDestinationChain must be a u16 (0..65535), got ${params.evmDestinationChain}`);
133
- }
134
130
  const out = routeWormholeCall({
135
131
  package: queuePkg(client),
136
132
  arguments: {
137
- evmDestinationChain: params.evmDestinationChain,
133
+ evmDestinationChain: toU16(params.evmDestinationChain, "evmDestinationChain"),
138
134
  evmRecipient: toEvmAddressBytes(params.evmRecipient, "evmRecipient"),
139
135
  evmToken: toEvmAddressBytes(params.evmToken, "evmToken"),
140
136
  },
@@ -145,7 +141,7 @@ export function routeWormhole(client, tx, params) {
145
141
  export function routeNative(client, tx, params) {
146
142
  const out = routeNativeCall({
147
143
  package: queuePkg(client),
148
- arguments: { minOutput: BigInt(params.minOutput ?? 0n) },
144
+ arguments: { minOutput: toU64(params.minOutput ?? 0n, "minOutput") },
149
145
  typeArguments: [normalizeStructTag(params.assetType)],
150
146
  })(tx);
151
147
  return out;
@@ -163,7 +159,7 @@ export function requestCreditWithdraw(client, tx, params) {
163
159
  registry: tx.object(client.config.packages.waterx_account.account_registry),
164
160
  senderRequest: senderRequest,
165
161
  accountId: params.accountId,
166
- amount: params.amount,
162
+ amount: toU64(params.amount, "amount"),
167
163
  recipient: params.recipient,
168
164
  extraData: params.route,
169
165
  },
@@ -194,7 +190,7 @@ export function executeWithdrawalWormhole(client, tx, params) {
194
190
  package: queuePkg(client),
195
191
  arguments: {
196
192
  queue: tx.object(queueId(client)),
197
- key: params.key,
193
+ key: toU64(params.key, "key"),
198
194
  request: request,
199
195
  bridge: tx.object(bridgeId(client)),
200
196
  creditRegistry: tx.object(creditRegistryId(client)),
@@ -211,7 +207,7 @@ export function executeWithdrawalNative(client, tx, params) {
211
207
  package: queuePkg(client),
212
208
  arguments: {
213
209
  queue: tx.object(queueId(client)),
214
- key: params.key,
210
+ key: toU64(params.key, "key"),
215
211
  request: request,
216
212
  vault: tx.object(custodyVaultId(client)),
217
213
  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,6 +1,6 @@
1
1
  // Shared, line-agnostic primitives (network id, scaling, decimals, time).
2
- // Perp-domain enums (permissions / order tags / action codes / fee rates) live
3
- // in `perp/constants.ts`; prediction has its own `prediction/constants.ts`.
2
+ // Perp-domain enums (permissions / order tags / action codes) live in
3
+ // `perp/constants.ts`; prediction has its own `prediction/constants.ts`.
4
4
  // ======== Scaling ========
5
5
  /** Basis-point denominator (10_000). Matches BP_SCALE in the Move contracts. */
6
6
  export const BPS_SCALE = 10000n;
@@ -13,7 +13,19 @@ export const DOUBLE_SCALE = 1000000000000000000n;
13
13
  export const SUI_DECIMALS = 9;
14
14
  /** WLP LP-token decimals. */
15
15
  export const WLP_DECIMALS = 6;
16
- /** Shared decimals for trading collateral / WLP backing assets (USDC, USDSUI). */
16
+ /**
17
+ * Decimals for **collateral-typed** values only: the CREDIT/wxUSD internal
18
+ * balance and the USD-pegged trading collateral (USDC, USDSUI). All current
19
+ * collateral and the CREDIT coin are 6-dec, and the config JSON carries no
20
+ * credit decimal, so this constant is the single source for the CREDIT scale.
21
+ *
22
+ * Do NOT use it for custody **backing assets** — those carry a per-asset
23
+ * `decimal` in config (`NativeCustodyAsset.decimal`), threaded through
24
+ * `probeParkedBackingAssets` → `sumParkedBackingAsCreditRaw`. If a 9-dec
25
+ * backing asset ever lists, a path that assumed flat 6 for it would mis-scale
26
+ * its parked balance by 1000×; only a change to the CREDIT coin itself (or a
27
+ * non-6-dec collateral listing) would require touching this constant.
28
+ */
17
29
  export const COLLATERAL_DECIMALS = 6;
18
30
  /**
19
31
  * @deprecated Import the individual `SUI_DECIMALS` / `WLP_DECIMALS` /
@@ -28,6 +40,8 @@ export const TOKEN_DECIMALS = {
28
40
  WLP: WLP_DECIMALS,
29
41
  };
30
42
  // ======== Time ========
43
+ export const MS_PER_MINUTE = 60 * 1000;
44
+ export const MS_PER_HOUR = 60 * 60 * 1000;
31
45
  export const MS_PER_YEAR = 365 * 24 * 60 * 60 * 1000;
32
46
  // ======== Well-known addresses ========
33
47
  /**
@@ -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,10 @@
1
+ /**************************************************************
2
+ * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
3
+ **************************************************************/
4
+ /** Module for floating points */
5
+ import { MoveStruct } from "../../../utils/index.js";
6
+ import { bcs } from '@mysten/sui/bcs';
7
+ const $moduleName = 'bucket_v2_framework::float';
8
+ export const Float = new MoveStruct({ name: `${$moduleName}::Float`, fields: {
9
+ value: bcs.u128()
10
+ } });
@@ -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,27 @@
1
+ /**************************************************************
2
+ * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
3
+ **************************************************************/
4
+ import { bcs } from '@mysten/sui/bcs';
5
+ import { MoveStruct } from "../../../utils/index.js";
6
+ const $moduleName = '0x2::vec_map';
7
+ /** An entry in the map */
8
+ export function Entry(...typeParameters) {
9
+ return new MoveStruct({ name: `${$moduleName}::Entry<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
10
+ key: typeParameters[0],
11
+ value: typeParameters[1]
12
+ } });
13
+ }
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 function VecMap(...typeParameters) {
24
+ return new MoveStruct({ name: `${$moduleName}::VecMap<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
25
+ contents: bcs.vector(Entry(typeParameters[0], typeParameters[1]))
26
+ } });
27
+ }