@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.
- package/README.md +37 -17
- package/dist/cjs/src/account/account.js +2 -1
- package/dist/cjs/src/account/config.d.ts +3 -2
- package/dist/cjs/src/account/funding/balance.d.ts +25 -2
- package/dist/cjs/src/account/funding/balance.js +36 -24
- package/dist/cjs/src/account/funding/credit.js +6 -10
- package/dist/cjs/src/constants.d.ts +15 -1
- package/dist/cjs/src/constants.js +18 -4
- package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
- package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +13 -0
- package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
- package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.js +31 -0
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +813 -0
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +946 -0
- package/dist/cjs/src/oracle/aggregate.d.ts +23 -21
- package/dist/cjs/src/oracle/aggregate.js +133 -59
- package/dist/cjs/src/oracle/config.d.ts +82 -41
- package/dist/cjs/src/oracle/config.js +0 -42
- package/dist/cjs/src/oracle/host.d.ts +26 -11
- package/dist/cjs/src/oracle/index.d.ts +6 -2
- package/dist/cjs/src/oracle/index.js +36 -8
- package/dist/cjs/src/oracle/price-update-rule.d.ts +16 -10
- package/dist/cjs/src/oracle/price-update-rule.js +3 -3
- package/dist/cjs/src/oracle/pyth.d.ts +44 -0
- package/dist/cjs/src/oracle/pyth.js +48 -6
- package/dist/cjs/src/oracle/read-plane.d.ts +70 -0
- package/dist/cjs/src/oracle/read-plane.js +78 -0
- package/dist/cjs/src/oracle/rule-registry.d.ts +14 -11
- package/dist/cjs/src/oracle/rule-registry.js +16 -11
- package/dist/cjs/src/oracle/rules/pyth-core-rule.js +4 -4
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +29 -4
- package/dist/cjs/src/oracle/rules/pyth-rule.js +5 -4
- package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +126 -0
- package/dist/cjs/src/oracle/rules/waterx-rule.js +312 -0
- package/dist/cjs/src/perp/client.d.ts +71 -20
- package/dist/cjs/src/perp/client.js +35 -13
- package/dist/cjs/src/perp/config.d.ts +6 -7
- package/dist/cjs/src/perp/config.js +12 -11
- package/dist/cjs/src/perp/constants.d.ts +0 -6
- package/dist/cjs/src/perp/constants.js +11 -9
- package/dist/cjs/src/perp/fetch/account.js +3 -0
- package/dist/cjs/src/perp/fetch/bridge.js +2 -1
- package/dist/cjs/src/perp/fetch/market.js +2 -1
- package/dist/cjs/src/perp/fetch/positions.d.ts +16 -10
- package/dist/cjs/src/perp/fetch/positions.js +23 -20
- package/dist/cjs/src/perp/index.d.ts +9 -5
- package/dist/cjs/src/perp/index.js +16 -7
- package/dist/cjs/src/perp/liq-view.d.ts +64 -0
- package/dist/cjs/src/perp/liq-view.js +74 -0
- package/dist/cjs/src/perp/user/order.d.ts +13 -0
- package/dist/cjs/src/perp/user/order.js +30 -16
- package/dist/cjs/src/perp/user/staking.js +3 -2
- package/dist/cjs/src/perp/user/trading.js +25 -24
- package/dist/cjs/src/perp/user/wlp.js +6 -5
- package/dist/cjs/src/prediction/utils.d.ts +11 -2
- package/dist/cjs/src/prediction/utils.js +22 -22
- package/dist/cjs/src/unified-client.d.ts +41 -15
- package/dist/cjs/src/unified-client.js +4 -2
- package/dist/cjs/src/utils/format.d.ts +14 -0
- package/dist/cjs/src/utils/format.js +24 -0
- package/dist/cjs/src/utils/math.d.ts +304 -12
- package/dist/cjs/src/utils/math.js +397 -17
- package/dist/cjs/src/utils/validate.d.ts +69 -0
- package/dist/cjs/src/utils/validate.js +183 -0
- package/dist/src/account/account.js +2 -1
- package/dist/src/account/config.d.ts +3 -2
- package/dist/src/account/funding/balance.d.ts +25 -2
- package/dist/src/account/funding/balance.js +36 -24
- package/dist/src/account/funding/credit.js +6 -10
- package/dist/src/constants.d.ts +15 -1
- package/dist/src/constants.js +17 -3
- package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
- package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +10 -0
- package/dist/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
- package/dist/src/generated/waterx_rule/deps/sui/vec_map.js +27 -0
- package/dist/src/generated/waterx_rule/waterx_rule.d.ts +813 -0
- package/dist/src/generated/waterx_rule/waterx_rule.js +855 -0
- package/dist/src/oracle/aggregate.d.ts +23 -21
- package/dist/src/oracle/aggregate.js +133 -59
- package/dist/src/oracle/config.d.ts +82 -41
- package/dist/src/oracle/config.js +1 -41
- package/dist/src/oracle/host.d.ts +26 -11
- package/dist/src/oracle/index.d.ts +6 -2
- package/dist/src/oracle/index.js +27 -9
- package/dist/src/oracle/price-update-rule.d.ts +16 -10
- package/dist/src/oracle/price-update-rule.js +3 -3
- package/dist/src/oracle/pyth.d.ts +44 -0
- package/dist/src/oracle/pyth.js +45 -5
- package/dist/src/oracle/read-plane.d.ts +70 -0
- package/dist/src/oracle/read-plane.js +74 -0
- package/dist/src/oracle/rule-registry.d.ts +14 -11
- package/dist/src/oracle/rule-registry.js +16 -11
- package/dist/src/oracle/rules/pyth-core-rule.js +5 -5
- package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
- package/dist/src/oracle/rules/pyth-lazer-rule.js +28 -3
- package/dist/src/oracle/rules/pyth-rule.js +5 -4
- package/dist/src/oracle/rules/waterx-rule.d.ts +126 -0
- package/dist/src/oracle/rules/waterx-rule.js +305 -0
- package/dist/src/perp/client.d.ts +71 -20
- package/dist/src/perp/client.js +36 -14
- package/dist/src/perp/config.d.ts +6 -7
- package/dist/src/perp/config.js +11 -9
- package/dist/src/perp/constants.d.ts +0 -6
- package/dist/src/perp/constants.js +10 -8
- package/dist/src/perp/fetch/account.js +3 -0
- package/dist/src/perp/fetch/bridge.js +2 -1
- package/dist/src/perp/fetch/market.js +2 -1
- package/dist/src/perp/fetch/positions.d.ts +16 -10
- package/dist/src/perp/fetch/positions.js +28 -20
- package/dist/src/perp/index.d.ts +9 -5
- package/dist/src/perp/index.js +6 -4
- package/dist/src/perp/liq-view.d.ts +64 -0
- package/dist/src/perp/liq-view.js +71 -0
- package/dist/src/perp/user/order.d.ts +13 -0
- package/dist/src/perp/user/order.js +30 -16
- package/dist/src/perp/user/staking.js +3 -2
- package/dist/src/perp/user/trading.js +25 -24
- package/dist/src/perp/user/wlp.js +6 -5
- package/dist/src/prediction/utils.d.ts +11 -2
- package/dist/src/prediction/utils.js +22 -22
- package/dist/src/unified-client.d.ts +41 -15
- package/dist/src/unified-client.js +4 -2
- package/dist/src/utils/format.d.ts +14 -0
- package/dist/src/utils/format.js +21 -0
- package/dist/src/utils/math.d.ts +304 -12
- package/dist/src/utils/math.js +394 -17
- package/dist/src/utils/validate.d.ts +69 -0
- package/dist/src/utils/validate.js +167 -0
- package/package.json +4 -1
package/dist/src/utils/math.d.ts
CHANGED
|
@@ -1,8 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Perp / WLP number math: Move-mirroring formulas, the `Float` fixed-point
|
|
3
|
+
* mirrors the canonical raw estimates need, and the on-chain price encoding.
|
|
4
|
+
*
|
|
5
|
+
* ## Validation policy — two tiers, deliberate
|
|
6
|
+
*
|
|
7
|
+
* The per-function `@throws` blocks below are INSTANCES of this rule, not a
|
|
8
|
+
* dozen independent decisions — every tier-1 function carries one. Guards come
|
|
9
|
+
* from `utils/validate.ts` (`assertFinite` / `assertFiniteNonNegative` /
|
|
10
|
+
* `assertUnitFraction` / `assertTokenDecimal` / `assertUnsignedBigInt`) and
|
|
11
|
+
* every message names the offending parameter.
|
|
12
|
+
*
|
|
13
|
+
* 1. **MONEY PATH — throws `RangeError`.** The fee bundles
|
|
14
|
+
* (`calcRealLiqNetCostUsd`, `calcViewEstLiqFeesUsd`), the liquidation
|
|
15
|
+
* estimates (`calcEstLiqPrice`, `calcEstLiqPriceRaw`), collateral and
|
|
16
|
+
* withdrawable (`calcEffectiveCollateralUsd`,
|
|
17
|
+
* `calcMaxReducibleCollateralUsd`), and the WLP quote / APY surface
|
|
18
|
+
* (`calcWlpMintOut`, `calcWlpRedeemOut`, `calcDynamicFeeBps`,
|
|
19
|
+
* `annualizedApyFromRatio`, `calcWlpIncentiveApy`). These map garbage onto a
|
|
20
|
+
* PLAUSIBLE number — an `Infinity` fee returns 0, indistinguishable from
|
|
21
|
+
* "already liquidatable"; a negative fee ADDS to equity — so the input dies
|
|
22
|
+
* at the boundary instead of becoming a wrong price on a screen.
|
|
23
|
+
* 2. **BARE ARITHMETIC — no guards.** Mostly one-line helpers (`calcNotional`,
|
|
24
|
+
* `calcFee`, `calcUnrealizedPnl`, `calcLeverage`, `calcTotalTradingFeeRate`,
|
|
25
|
+
* `calcFundingRate`, `calcFundingFeeUsd`, `decodeFundingIndexDelta`,
|
|
26
|
+
* `calcBorrowRate`, `calcBorrowRateAccrual`, `calcPositionBorrowFee`,
|
|
27
|
+
* `calcTokenUtilizationBps`, `annualizeFundingRate`, `calcWlpPrice`), plus
|
|
28
|
+
* `calcImpactFeeRate` — NOT a one-liner (a branchy curve with eight early
|
|
29
|
+
* returns) but the same category: each of its early returns tests an exact
|
|
30
|
+
* zero or an ordering that a NaN never satisfies, so garbage falls straight
|
|
31
|
+
* through the branches instead of being absorbed by one. A NaN / Infinity
|
|
32
|
+
* input propagates VISIBLY to the output in all of them — there is no
|
|
33
|
+
* plausible-looking value for it to hide behind — so a guard would add noise
|
|
34
|
+
* and cost without buying safety.
|
|
35
|
+
*
|
|
36
|
+
* `rawPrice` sits in neither tier: it is a PARSE, and throws plain `Error` on
|
|
37
|
+
* malformed input.
|
|
38
|
+
*
|
|
39
|
+
* ### Documented domain zeros
|
|
40
|
+
* Distinct from garbage: an input that is legitimately zero and has exactly one
|
|
41
|
+
* honest answer returns it rather than throwing. `sizeInAsset === 0` /
|
|
42
|
+
* `entryNotional === 0` → `0` (nothing to liquidate); `totalSupply === 0` → `0`
|
|
43
|
+
* (no shares to price — `calcWlpMintOut` is the deliberate exception, where it
|
|
44
|
+
* means the bootstrap mint); `intervalMs === 0` / `days <= 0` → `0` (no window
|
|
45
|
+
* to annualize over); `liquidityAmount === 0` → `0` utilization;
|
|
46
|
+
* `collateralUsd === 0` → `Infinity` leverage. Each is noted at its function.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* A USD price as a plain decimal STRING (`"95000"` / `"95000.5"`) — the EXACT
|
|
50
|
+
* mode of `rawPrice`.
|
|
51
|
+
*
|
|
52
|
+
* The digits are parsed straight onto the 1e9 grid with no f64 round-trip, so
|
|
53
|
+
* the conversion is digit-exact at any magnitude (up to 9 decimal places;
|
|
54
|
+
* `rawPrice` throws on malformed input, a leading `-`, scientific notation, or
|
|
55
|
+
* >9 decimals, which the grid cannot represent).
|
|
56
|
+
*
|
|
57
|
+
* Prefer this mode for any price that is an EXACT KEY rather than a bound —
|
|
58
|
+
* above all `triggerPrice`, where a raw value off by a single 1e-9 unit
|
|
59
|
+
* silently fails the order-book lookup.
|
|
60
|
+
*/
|
|
61
|
+
export type ExactDecimalUsd = string;
|
|
62
|
+
/**
|
|
63
|
+
* Accepted input to `rawPrice`, in two DELIBERATELY different modes:
|
|
64
|
+
*
|
|
65
|
+
* - `number` — LOSSY above the f64 cliff. Exact only while `usd × 1e9` stays
|
|
66
|
+
* within 2^53 (i.e. below ≈ $9,007,199), and even below that a non-binary
|
|
67
|
+
* fraction rounds to the nearest representable double before scaling.
|
|
68
|
+
* Fine for slippage bounds (`acceptablePrice`), where ±1 raw unit is noise.
|
|
69
|
+
* - {@link ExactDecimalUsd} (`string`) — digit-exact at any magnitude. Use for
|
|
70
|
+
* exact order-book keys (`triggerPrice`).
|
|
71
|
+
*
|
|
72
|
+
* The union is NOT "either works": picking `number` for an exact key is the
|
|
73
|
+
* documented footgun this alias exists to surface at the call site.
|
|
74
|
+
*/
|
|
75
|
+
export type RawPriceInput = number | ExactDecimalUsd;
|
|
1
76
|
/**
|
|
2
77
|
* Convert a human-readable USD price to the raw 1e9-scaled `u128` value
|
|
3
78
|
* that on-chain `Float`-typed parameters expect.
|
|
79
|
+
*
|
|
80
|
+
* Use for **tx-build** price args only (`acceptablePrice` / `triggerPrice` /
|
|
81
|
+
* size args). Do NOT use for the view-read params `basePriceUsd` /
|
|
82
|
+
* `collateralPriceUsd` on `perp/fetch` (`getPosition`, `getMarketPositions`,
|
|
83
|
+
* `getOrder`, …) — those take WHOLE-DOLLAR integer USD (the Move view applies
|
|
84
|
+
* `float::from` internally; a 1e9-scaled value inflates pnl/notional-derived
|
|
85
|
+
* fields by 1e9).
|
|
86
|
+
*
|
|
87
|
+
* Precision: see {@link RawPriceInput}. The `number` path rounds through f64
|
|
88
|
+
* and is exact only below ≈ $9,007,199; an {@link ExactDecimalUsd} string
|
|
89
|
+
* parses digits directly onto the 1e9 grid without touching f64. This bites
|
|
90
|
+
* hardest on `triggerPrice`, which is an EXACT order-book key: a raw value off
|
|
91
|
+
* by one unit silently fails the order lookup.
|
|
4
92
|
*/
|
|
5
|
-
export declare function rawPrice(usd:
|
|
93
|
+
export declare function rawPrice(usd: RawPriceInput): bigint;
|
|
6
94
|
/** Notional value in USD: sizeInAsset × price. */
|
|
7
95
|
export declare function calcNotional(sizeInAsset: number, price: number): number;
|
|
8
96
|
/** Trading fee in USD: notional × feeRate. */
|
|
@@ -12,9 +100,89 @@ export declare function calcUnrealizedPnl(isLong: boolean, entryPrice: number, s
|
|
|
12
100
|
/** Position leverage = notional / collateralUsd. Returns Infinity when collateral is zero. */
|
|
13
101
|
export declare function calcLeverage(sizeUsd: number, collateralUsd: number): number;
|
|
14
102
|
/**
|
|
15
|
-
*
|
|
103
|
+
* Accrued-fee inputs for the REAL-model liquidation estimate — see
|
|
104
|
+
* `calcRealLiqNetCostUsd` for the rule and the Move-semantics note.
|
|
105
|
+
*
|
|
106
|
+
* `fundingFeeUsd` is SIGNED, cost-positive: > 0 the position owes funding,
|
|
107
|
+
* < 0 is funding income (a genuine equity credit, applied in full).
|
|
108
|
+
*/
|
|
109
|
+
export type LiqFeeBundle = {
|
|
110
|
+
borrowFeeUsd: number;
|
|
111
|
+
openFeeUsd: number;
|
|
112
|
+
closingFeeUsd: number;
|
|
113
|
+
/** SIGNED, cost-positive: > 0 owed, < 0 income (credits equity in full). */
|
|
114
|
+
fundingFeeUsd: number;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Net fee cost (USD) of the REAL liquidation check — a plain SIGNED sum:
|
|
118
|
+
*
|
|
119
|
+
* netCostUsd = borrowFeeUsd + openFeeUsd + closingFeeUsd + fundingFeeUsd
|
|
120
|
+
*
|
|
121
|
+
* `fundingFeeUsd` is SIGNED cost-positive, and the result MAY BE NEGATIVE
|
|
122
|
+
* when funding income exceeds the other fees. That is deliberate:
|
|
123
|
+
* `position.move::is_liquidatable` credits funding income IN FULL — income
|
|
124
|
+
* first pays down any accumulated deficit, and the remainder is added back to
|
|
125
|
+
* remaining equity — so the linearized equity model is a plain signed sum
|
|
126
|
+
* with no floor. Flooring at 0 here would understate an income-rich
|
|
127
|
+
* position's equity and show a liq price closer to spot than the real check.
|
|
128
|
+
*
|
|
129
|
+
* Three-way Move-semantics relationship (verified against the Move sources
|
|
130
|
+
* 2026-07-30):
|
|
131
|
+
* - the REAL liquidation check, `position.move::is_liquidatable`
|
|
132
|
+
* (waterx_perp): deducts borrow + open + CLOSING fee and credits funding
|
|
133
|
+
* income in full (deficit first, remainder back to equity) — exactly this
|
|
134
|
+
* function's signed sum;
|
|
135
|
+
* - the view estimate, `view.move::calculate_est_liq_price`
|
|
136
|
+
* (waterx_perp_view): OMITS the closing fee AND floors its fee bundle at 0
|
|
137
|
+
* (`Float.saturating_sub` — Float is unsigned) — see `calcViewEstLiqFeesUsd`
|
|
138
|
+
* and the op-exact `calcEstLiqPriceRaw`;
|
|
139
|
+
* - SDK `calcEffectiveCollateralUsd` does NOT credit funding income at all:
|
|
140
|
+
* it mirrors the withdrawable-collateral checks
|
|
141
|
+
* (`calculate_effective_collateral_amount` in `trading.move`), not the
|
|
142
|
+
* liquidation inequality.
|
|
143
|
+
* Do not "fix" any of the three to match another.
|
|
144
|
+
*
|
|
145
|
+
* @throws RangeError when borrow/open/closing fees are not finite `>= 0`
|
|
146
|
+
* numbers, or `fundingFeeUsd` is not finite.
|
|
147
|
+
*/
|
|
148
|
+
export declare function calcRealLiqNetCostUsd(fees: LiqFeeBundle): number;
|
|
149
|
+
/**
|
|
150
|
+
* Fee bundle (USD) of the VIEW estimate `view.move::calculate_est_liq_price`:
|
|
151
|
+
*
|
|
152
|
+
* viewFeesUsd = max(0, borrowFeeUsd + openFeeUsd + fundingFeeUsd)
|
|
153
|
+
*
|
|
154
|
+
* Mirrors the view's unsigned Float arithmetic: funding income is credited
|
|
155
|
+
* via `Float.saturating_sub`, so the bundle FLOORS AT 0 — income beyond the
|
|
156
|
+
* other fees is discarded by the view. There is deliberately NO
|
|
157
|
+
* `closingFeeUsd` field: the view omits the close-fee term, and this shape
|
|
158
|
+
* makes it structurally impossible to include one. For the REAL liquidation
|
|
159
|
+
* check's semantics use `calcRealLiqNetCostUsd`; for chain-bit-identical
|
|
160
|
+
* output use `calcEstLiqPriceRaw`.
|
|
161
|
+
*
|
|
162
|
+
* Exported on purpose even though `calcEstLiqPriceRaw` covers the chain-exact
|
|
163
|
+
* path: this is the VIEW-model counterpart of `calcRealLiqNetCostUsd`, for
|
|
164
|
+
* consumers that need the view's fee bundle as a Number (mirroring what the
|
|
165
|
+
* view displays) rather than the full raw price. The two-API split is what makes
|
|
166
|
+
* the REAL and VIEW models impossible to confuse — do not fold it away.
|
|
167
|
+
*
|
|
168
|
+
* @throws RangeError when borrow/open fees are not finite `>= 0` numbers, or
|
|
169
|
+
* `fundingFeeUsd` is not finite.
|
|
170
|
+
*/
|
|
171
|
+
export declare function calcViewEstLiqFeesUsd(fees: {
|
|
172
|
+
borrowFeeUsd: number;
|
|
173
|
+
openFeeUsd: number;
|
|
174
|
+
/** SIGNED, cost-positive: > 0 owed, < 0 income (bundle floors at 0). */
|
|
175
|
+
fundingFeeUsd: number;
|
|
176
|
+
}): number;
|
|
177
|
+
/**
|
|
178
|
+
* Estimated liquidation price — Number (f64) UI convenience.
|
|
179
|
+
*
|
|
180
|
+
* An approximation for display. The CANONICAL implementation is
|
|
181
|
+
* `calcEstLiqPriceRaw` (BigInt fixed-point, op-for-op mirror of
|
|
182
|
+
* `calculate_est_liq_price` in `waterx_perp_view/sources/view.move`); use that
|
|
183
|
+
* wherever exact parity with the on-chain `est_liq_price` matters.
|
|
16
184
|
*
|
|
17
|
-
*
|
|
185
|
+
* Same linear model as the view:
|
|
18
186
|
* maintenance = maintenanceMarginRate × (size × spotPrice) ← uses current notional
|
|
19
187
|
* ratio = (collateralUsd − totalFeesUsd − maintenance) / (size × avgPrice)
|
|
20
188
|
* long: liq = avgPrice × (1 − ratio)
|
|
@@ -22,7 +190,24 @@ export declare function calcLeverage(sizeUsd: number, collateralUsd: number): nu
|
|
|
22
190
|
*
|
|
23
191
|
* Returns 0 when the position is already liquidatable or has no size.
|
|
24
192
|
*
|
|
25
|
-
*
|
|
193
|
+
* Fees — pass EITHER:
|
|
194
|
+
* - `fees`: the structured bundle, matching the REAL liquidation check
|
|
195
|
+
* (`position.move::is_liquidatable`). `totalFeesUsd` is derived via
|
|
196
|
+
* `calcRealLiqNetCostUsd` — a SIGNED sum including the closing fee, with
|
|
197
|
+
* funding income credited IN FULL, so a caller structurally cannot omit a
|
|
198
|
+
* term or mis-handle income. A negative net cost ADDS to the remaining
|
|
199
|
+
* margin, pushing the estimate FARTHER from spot. Takes precedence when
|
|
200
|
+
* both are given; or
|
|
201
|
+
* - `totalFeesUsd`: a pre-computed number (back-compat path) — the caller
|
|
202
|
+
* owns the fee model.
|
|
203
|
+
* NOTE the deliberate model difference vs the on-chain VIEW: the view both
|
|
204
|
+
* floors its fee bundle at 0 and omits the close fee (`calcViewEstLiqFeesUsd`
|
|
205
|
+
* / `calcEstLiqPriceRaw`); the `fees` path here matches the REAL check.
|
|
206
|
+
*
|
|
207
|
+
* @throws RangeError when sizeInAsset / avgPrice / spotPrice / collateralUsd
|
|
208
|
+
* are not finite `>= 0` numbers, when `maintenanceMarginRate` is not finite
|
|
209
|
+
* inside `[0, 1]`, or when `totalFeesUsd` is not finite.
|
|
210
|
+
* (`sizeInAsset === 0` stays a documented domain case returning 0.)
|
|
26
211
|
*/
|
|
27
212
|
export declare function calcEstLiqPrice(params: {
|
|
28
213
|
isLong: boolean;
|
|
@@ -31,8 +216,74 @@ export declare function calcEstLiqPrice(params: {
|
|
|
31
216
|
collateralUsd: number;
|
|
32
217
|
maintenanceMarginRate: number;
|
|
33
218
|
spotPrice: number;
|
|
219
|
+
} & ({
|
|
34
220
|
totalFeesUsd: number;
|
|
35
|
-
|
|
221
|
+
fees?: LiqFeeBundle;
|
|
222
|
+
} | {
|
|
223
|
+
totalFeesUsd?: number;
|
|
224
|
+
fees: LiqFeeBundle;
|
|
225
|
+
})): number;
|
|
226
|
+
/**
|
|
227
|
+
* Estimated liquidation price — CANONICAL raw fixed-point implementation.
|
|
228
|
+
*
|
|
229
|
+
* Op-for-op mirror of `calculate_est_liq_price` in
|
|
230
|
+
* `waterx_perp_view/sources/view.move` under `bucket_v2_framework::float`
|
|
231
|
+
* semantics: unsigned 1e9 fixed-point, every `mul` is `(a×b)/1e9` and every
|
|
232
|
+
* `div` is `(a×1e9)/b` with truncating BigInt division at EACH step,
|
|
233
|
+
* including `math::amount_to_usd`'s exact composition, the u64 addition of
|
|
234
|
+
* borrow + open fee BEFORE the USD conversion, and the `saturating_sub`
|
|
235
|
+
* funding credit (the VIEW model: fee bundle floors at 0, close fee omitted).
|
|
236
|
+
* Given the same raw inputs the view receives, the result is bit-identical to
|
|
237
|
+
* the chain's `PositionData.est_liq_price`.
|
|
238
|
+
*
|
|
239
|
+
* The Number `calcEstLiqPrice` is a UI convenience approximation of this
|
|
240
|
+
* canonical form (and its `fees` path models the REAL liquidation check
|
|
241
|
+
* instead of the view — see `calcRealLiqNetCostUsd`).
|
|
242
|
+
*
|
|
243
|
+
* Inputs are the raw on-chain values exactly as the view takes them.
|
|
244
|
+
* Returns the raw 1e9-scaled u128 price; `0n` = already liquidatable /
|
|
245
|
+
* zero size (the view's N/A signal).
|
|
246
|
+
*
|
|
247
|
+
* Holding a fetched `PositionDataView` row? Use `calcEstLiqPriceRawFromView`
|
|
248
|
+
* (`perp/liq-view.ts`) instead of hand-mapping its nine raw fields — the adapter
|
|
249
|
+
* owns that mapping and carries the invariant below on its own signature.
|
|
250
|
+
*
|
|
251
|
+
* INVARIANT the signature cannot enforce: `basePriceUsd` / `collateralPriceUsd`
|
|
252
|
+
* MUST be the same whole-dollar values passed to the `perp/fetch` read that
|
|
253
|
+
* produced the row whose fields you are feeding in. `PositionDataView` does not
|
|
254
|
+
* carry the probe prices, so nothing here can check it — feed different prices
|
|
255
|
+
* and the fee/notional-derived fields were computed against one price while the
|
|
256
|
+
* estimate is computed against another, and parity with
|
|
257
|
+
* `PositionData.est_liq_price` silently breaks.
|
|
258
|
+
*
|
|
259
|
+
* @throws RangeError when any bigint input is negative or
|
|
260
|
+
* `collateralDecimal` is not an integer in `[0, 19]` (u64 `10^decimal`).
|
|
261
|
+
*/
|
|
262
|
+
export declare function calcEstLiqPriceRaw(params: {
|
|
263
|
+
isLong: boolean;
|
|
264
|
+
/** `PositionData.size` — raw 1e9-scaled Float value. */
|
|
265
|
+
sizeRaw: bigint;
|
|
266
|
+
/** `PositionData.average_price` — raw 1e9-scaled Float value. */
|
|
267
|
+
avgPriceRaw: bigint;
|
|
268
|
+
/** `PositionData.collateral_amount` — raw collateral token units. */
|
|
269
|
+
collateralAmountRaw: bigint;
|
|
270
|
+
/** `PositionData.collateral_decimal`. */
|
|
271
|
+
collateralDecimal: number;
|
|
272
|
+
/** Whole-dollar u64 base price — the exact value passed to the view (pre `float::from`). */
|
|
273
|
+
basePriceUsd: bigint;
|
|
274
|
+
/** Whole-dollar u64 collateral price — the exact value passed to the view (pre `float::from`). */
|
|
275
|
+
collateralPriceUsd: bigint;
|
|
276
|
+
/** `MarketData.maintenance_margin` — raw 1e9-scaled Float value. */
|
|
277
|
+
maintenanceMarginRaw: bigint;
|
|
278
|
+
/** `PositionData.borrow_fee` (accrued + unrealized, pre-combined by the view) — raw collateral units. */
|
|
279
|
+
borrowFeeRaw: bigint;
|
|
280
|
+
/** `PositionData.funding_fee_positive` — true when the position owes funding. */
|
|
281
|
+
fundingSign: boolean;
|
|
282
|
+
/** `PositionData.funding_fee` magnitude — raw collateral units. */
|
|
283
|
+
fundingFeeRaw: bigint;
|
|
284
|
+
/** `PositionData.unrealized_trading_fee` (open fee) — raw collateral units. */
|
|
285
|
+
tradingFeeRaw: bigint;
|
|
286
|
+
}): bigint;
|
|
36
287
|
/**
|
|
37
288
|
* Effective (fee-adjusted) collateral in USD.
|
|
38
289
|
*
|
|
@@ -53,9 +304,11 @@ export declare function calcEstLiqPrice(params: {
|
|
|
53
304
|
* @param grossCollateralUsd Position collateral in USD (`collateral_amount` → USD).
|
|
54
305
|
* @param borrowFeeUsd `unrealized_borrow_fee` in USD.
|
|
55
306
|
* @param fundingSign `unrealized_funding_sign` — true when the position owes funding.
|
|
56
|
-
* @param fundingFeeUsd `unrealized_funding_fee` magnitude in USD.
|
|
307
|
+
* @param fundingFeeUsd `unrealized_funding_fee` magnitude in USD (unsigned; sign travels separately).
|
|
57
308
|
* @param tradingFeeUsd `unrealized_trading_fee` in USD.
|
|
58
309
|
* @param projectedTradingFeeUsd Closing fee to reserve (0 for a bare collateral withdrawal).
|
|
310
|
+
* @throws RangeError when any USD input is not a finite `>= 0` number — a
|
|
311
|
+
* negative fee would silently ADD to effective collateral.
|
|
59
312
|
*/
|
|
60
313
|
export declare function calcEffectiveCollateralUsd(params: {
|
|
61
314
|
grossCollateralUsd: number;
|
|
@@ -101,6 +354,16 @@ export declare function calcEffectiveCollateralUsd(params: {
|
|
|
101
354
|
* @param closingFeeUsd Full closing fee in USD (`close_fee` → USD).
|
|
102
355
|
* @param collateralPriceUsd Oracle price of the collateral token (USD per token).
|
|
103
356
|
* @param collateralDecimal Collateral token decimals — sets the smallest withdraw step.
|
|
357
|
+
* @throws RangeError when any USD / size / price input is not a finite `>= 0`
|
|
358
|
+
* number, when `maintenanceMarginRate` is not finite inside `[0, 1]`, or when
|
|
359
|
+
* `collateralDecimal` is not an integer in `[0, 19]` — the same domains
|
|
360
|
+
* `calcEstLiqPrice` / `calcEstLiqPriceRaw` enforce. Two of these are the
|
|
361
|
+
* reason the whole set is here: a negative fee silently INFLATES the
|
|
362
|
+
* withdrawable amount, and a negative `collateralPriceUsd` drops the
|
|
363
|
+
* one-raw-unit liquidation back-off to 0 — removing the abort-safety margin
|
|
364
|
+
* while still returning a plausible-looking dollar figure.
|
|
365
|
+
* (`maxLeverage === 0` → no leverage cap and `collateralPriceUsd === 0` → no
|
|
366
|
+
* back-off stay documented domain zeros, not garbage.)
|
|
104
367
|
*/
|
|
105
368
|
export declare function calcMaxReducibleCollateralUsd(params: {
|
|
106
369
|
grossCollateralUsd: number;
|
|
@@ -192,8 +455,11 @@ export declare function calcBorrowRate(utilizationBps: number, rate0: number, ra
|
|
|
192
455
|
/**
|
|
193
456
|
* Time-weighted borrow rate accrual for a given elapsed period.
|
|
194
457
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
458
|
+
* Continuous proration: `rate × elapsedMs / intervalMs`, matching the formula
|
|
459
|
+
* of `lp_pool.move::calculate_borrow_rate_accrual`
|
|
460
|
+
* (`borrow_rate.mul_u64(elapsed_ms).div_u64(interval_ms)`) — the contract does
|
|
461
|
+
* NOT floor to completed intervals; a partial interval accrues pro rata
|
|
462
|
+
* (verified against the Move source 2026-07-29).
|
|
197
463
|
*/
|
|
198
464
|
export declare function calcBorrowRateAccrual(borrowRate: number, elapsedMs: number, intervalMs: number): number;
|
|
199
465
|
/**
|
|
@@ -220,19 +486,22 @@ export declare function annualizeFundingRate(rate: number, intervalMs: number):
|
|
|
220
486
|
* Annualized APY from a NAV ratio over a given number of days.
|
|
221
487
|
*
|
|
222
488
|
* Compounds `ratio` (WLP price now / WLP price past) to a 365-day return.
|
|
223
|
-
*
|
|
489
|
+
* Documented domain cases returning 0: `ratio <= 0` or `days <= 0` (no valid
|
|
490
|
+
* sample window), and an overflowing compound result.
|
|
224
491
|
*
|
|
225
492
|
* @param ratio Current NAV divided by past NAV (e.g. 1.05 for 5% growth).
|
|
226
493
|
* @param days Number of days elapsed between the two NAV samples.
|
|
494
|
+
* @throws RangeError when `ratio` or `days` is NaN / ±Infinity.
|
|
227
495
|
*/
|
|
228
496
|
export declare function annualizedApyFromRatio(ratio: number, days: number): number;
|
|
229
497
|
/**
|
|
230
498
|
* Convert a continuously-compounded incentive APR to APY.
|
|
231
499
|
*
|
|
232
500
|
* Rewards stream via `flow_rate` (continuous compounding), so APY = e^APR − 1.
|
|
233
|
-
* Returns 0 when the result
|
|
501
|
+
* Returns 0 when the compound result overflows to Infinity.
|
|
234
502
|
*
|
|
235
503
|
* @param apr Time-weighted incentive APR as a decimal fraction (e.g. 0.12 for 12%).
|
|
504
|
+
* @throws RangeError when `apr` is NaN / ±Infinity.
|
|
236
505
|
*/
|
|
237
506
|
export declare function calcWlpIncentiveApy(apr: number): number;
|
|
238
507
|
/**
|
|
@@ -248,12 +517,21 @@ export declare function calcWlpPrice(tvlUsd: number, totalSupply: number, lpDeci
|
|
|
248
517
|
*
|
|
249
518
|
* Matches the LP-amount formula in `mint_wlp_with_pricing_tvl` in `lp_pool.move`.
|
|
250
519
|
* Pass `netDepositUsd` (after the dynamic mint fee is deducted).
|
|
251
|
-
*
|
|
520
|
+
*
|
|
521
|
+
* Bootstrap ($1/share par, `lpAmount = netDepositUsd × 10^lpDecimals`) applies
|
|
522
|
+
* ONLY to the genuine first mint (`totalSupply === 0`) — exactly like the
|
|
523
|
+
* chain. When supply is outstanding but the priced TVL has floored to 0 (e.g.
|
|
524
|
+
* trader unrealized profit ≥ TVL drove the equity `saturating_sub` to 0) the
|
|
525
|
+
* chain ABORTS `EInvalidBootstrap` rather than par-minting cheap shares that
|
|
526
|
+
* dilute existing LPs (re-audit F-023); this helper throws `RangeError` in
|
|
527
|
+
* that state instead of silently par-quoting.
|
|
252
528
|
*
|
|
253
529
|
* @param netDepositUsd Deposit value in USD after dynamic mint fee.
|
|
254
530
|
* @param tvlUsd Pool TVL in USD at pricing time.
|
|
255
531
|
* @param totalSupply Current total WLP supply in raw units.
|
|
256
532
|
* @param lpDecimals WLP token decimals (6).
|
|
533
|
+
* @throws RangeError when inputs are not finite `>= 0` numbers, or on the
|
|
534
|
+
* `totalSupply > 0 && tvlUsd === 0` state (chain aborts `EInvalidBootstrap`).
|
|
257
535
|
*/
|
|
258
536
|
export declare function calcWlpMintOut(netDepositUsd: number, tvlUsd: number, totalSupply: number, lpDecimals: number): number;
|
|
259
537
|
/**
|
|
@@ -262,11 +540,21 @@ export declare function calcWlpMintOut(netDepositUsd: number, tvlUsd: number, to
|
|
|
262
540
|
* Matches the settlement formula in `settle_redeem_with_pricing_tvl` in `lp_pool.move`.
|
|
263
541
|
* Apply `calcDynamicFeeBps` separately to get the net output.
|
|
264
542
|
*
|
|
543
|
+
* Chain-divergence notes (display-convenience helper, not settlement-exact):
|
|
544
|
+
* - `tokenPriceUsd === 0` returns 0 here, but the chain ABORTS (`EZeroPrice`,
|
|
545
|
+
* lp_pool.move) — a zero from this helper on that input is a display
|
|
546
|
+
* placeholder, not a real quote.
|
|
547
|
+
* - The burn fee is applied on-chain as
|
|
548
|
+
* `float::from_bps(fee_bps).mul_u64(raw_amount).ceil()` — composing this
|
|
549
|
+
* helper with `calcDynamicFeeBps` in f64 (which cannot `.ceil()` on the raw
|
|
550
|
+
* grid) can drift ±1 raw unit from the settled output.
|
|
551
|
+
*
|
|
265
552
|
* @param lpAmount LP tokens being redeemed (raw units).
|
|
266
553
|
* @param tvlUsd Pool TVL in USD at pricing time.
|
|
267
554
|
* @param totalSupply Current total WLP supply in raw units.
|
|
268
555
|
* @param tokenPriceUsd Oracle price of the output token.
|
|
269
556
|
* @param tokenDecimals Output token decimals.
|
|
557
|
+
* @throws RangeError when any numeric input is not a finite `>= 0` number.
|
|
270
558
|
*/
|
|
271
559
|
export declare function calcWlpRedeemOut(lpAmount: number, tvlUsd: number, totalSupply: number, tokenPriceUsd: number, tokenDecimals: number): number;
|
|
272
560
|
/**
|
|
@@ -275,7 +563,8 @@ export declare function calcWlpRedeemOut(lpAmount: number, tvlUsd: number, total
|
|
|
275
563
|
* Matches `calculate_dynamic_fee` in `lp_pool.move`. Returns `baseFeeBps` when
|
|
276
564
|
* the operation moves the token closer to (or does not worsen) its target weight.
|
|
277
565
|
* Adds an additional fee proportional to the average deviation when it moves
|
|
278
|
-
* further away.
|
|
566
|
+
* further away. Clamped to 100% (`bp_scale`) on both the additional term and
|
|
567
|
+
* the total, mirroring the on-chain F-039 clamp.
|
|
279
568
|
*
|
|
280
569
|
* @param tokenValueUsd Current USD value of this token in the pool.
|
|
281
570
|
* @param tvlUsd Total pool TVL in USD.
|
|
@@ -283,5 +572,8 @@ export declare function calcWlpRedeemOut(lpAmount: number, tvlUsd: number, total
|
|
|
283
572
|
* @param targetWeightBps Target allocation weight for this token (bps).
|
|
284
573
|
* @param baseFeeBps Base mint/burn fee (bps).
|
|
285
574
|
* @param isDeposit True for mint, false for redeem.
|
|
575
|
+
* @throws RangeError when any USD / bps input is not a finite `>= 0` number.
|
|
576
|
+
* (`tvlUsd` / `operationValueUsd` / `targetWeightBps` of exactly 0 stay
|
|
577
|
+
* documented domain cases returning `baseFeeBps` — nothing to deviate from.)
|
|
286
578
|
*/
|
|
287
579
|
export declare function calcDynamicFeeBps(tokenValueUsd: number, tvlUsd: number, operationValueUsd: number, targetWeightBps: number, baseFeeBps: number, isDeposit: boolean): number;
|