@mysten/deepbook-v3 2.5.0 → 2.6.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/CHANGELOG.md +31 -0
- package/PREDICT.md +160 -12
- package/dist/contracts/account/account.d.mts +23 -23
- package/dist/contracts/account/account.d.mts.map +1 -1
- package/dist/contracts/account/account_registry.d.mts +19 -19
- package/dist/contracts/account/account_registry.d.mts.map +1 -1
- package/dist/contracts/deepbook/account.d.mts +18 -18
- package/dist/contracts/deepbook/balances.d.mts +4 -4
- package/dist/contracts/deepbook/deep_price.d.mts +3 -3
- package/dist/contracts/deepbook_predict/admin.d.mts +4 -4
- package/dist/contracts/deepbook_predict/builder_code.d.mts +11 -11
- package/dist/contracts/deepbook_predict/builder_code.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/builder_code_events.d.mts +10 -10
- package/dist/contracts/deepbook_predict/config_events.d.mts +67 -67
- package/dist/contracts/deepbook_predict/config_events.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/expiry_market.d.mts +176 -96
- package/dist/contracts/deepbook_predict/expiry_market.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/expiry_market.mjs +114 -1
- package/dist/contracts/deepbook_predict/expiry_market.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/market_lifecycle_cap.d.mts +5 -5
- package/dist/contracts/deepbook_predict/market_manager.d.mts +27 -27
- package/dist/contracts/deepbook_predict/market_manager.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/order_events.d.mts +50 -50
- package/dist/contracts/deepbook_predict/pause_cap.d.mts +5 -5
- package/dist/contracts/deepbook_predict/plp.d.mts +72 -72
- package/dist/contracts/deepbook_predict/plp.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/pool_valuation_cap.d.mts +5 -5
- package/dist/contracts/deepbook_predict/predict_account.d.mts +14 -14
- package/dist/contracts/deepbook_predict/pricing.d.mts +53 -53
- package/dist/contracts/deepbook_predict/protocol_config.d.mts +64 -64
- package/dist/contracts/deepbook_predict/range_codec.d.mts +2 -2
- package/dist/contracts/deepbook_predict/registry.d.mts +28 -28
- package/dist/contracts/deepbook_predict/strike_exposure.mjs +12 -0
- package/dist/contracts/deepbook_predict/strike_exposure.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/vault_events.d.mts +105 -105
- package/dist/contracts/deepbook_sessions/session_config.d.mts +8 -8
- package/dist/contracts/deepbook_sessions/session_config.d.mts.map +1 -1
- package/dist/contracts/deepbook_sessions/sessions.d.mts +48 -23
- package/dist/contracts/deepbook_sessions/sessions.d.mts.map +1 -1
- package/dist/contracts/deepbook_sessions/sessions.mjs +44 -1
- package/dist/contracts/deepbook_sessions/sessions.mjs.map +1 -1
- package/dist/deployments/mainnet.d.mts.map +1 -1
- package/dist/deployments/mainnet.mjs +2 -0
- package/dist/deployments/mainnet.mjs.map +1 -1
- package/dist/deployments/testnet.d.mts.map +1 -1
- package/dist/deployments/testnet.mjs +4 -2
- package/dist/deployments/testnet.mjs.map +1 -1
- package/dist/deployments/types.d.mts +1 -1
- package/dist/predict/client.d.mts +12 -3
- package/dist/predict/client.d.mts.map +1 -1
- package/dist/predict/client.mjs +39 -18
- package/dist/predict/client.mjs.map +1 -1
- package/dist/predict/config/generated.d.mts +3 -2
- package/dist/predict/config/generated.d.mts.map +1 -1
- package/dist/predict/config/generated.mjs +1 -0
- package/dist/predict/config/generated.mjs.map +1 -1
- package/dist/predict/config/types.d.mts +3 -0
- package/dist/predict/config/types.d.mts.map +1 -1
- package/dist/predict/cost.d.mts +353 -0
- package/dist/predict/cost.d.mts.map +1 -0
- package/dist/predict/cost.mjs +555 -0
- package/dist/predict/cost.mjs.map +1 -0
- package/dist/predict/decode.mjs +6 -7
- package/dist/predict/decode.mjs.map +1 -1
- package/dist/predict/index.d.mts +3 -2
- package/dist/predict/index.mjs +2 -1
- package/dist/predict/pricing.mjs +1 -1
- package/dist/predict/reads/positions.mjs +1 -1
- package/dist/predict/reads/positions.mjs.map +1 -1
- package/dist/predict/tx/trade.d.mts.map +1 -1
- package/dist/predict/tx/trade.mjs +18 -2
- package/dist/predict/tx/trade.mjs.map +1 -1
- package/dist/sessions.d.mts +17 -1
- package/dist/sessions.d.mts.map +1 -1
- package/dist/sessions.mjs +22 -2
- package/dist/sessions.mjs.map +1 -1
- package/dist/transactions/balanceManager.d.mts +12 -12
- package/dist/transactions/balanceManager.d.mts.map +1 -1
- package/dist/transactions/deepbook.d.mts +20 -20
- package/dist/transactions/deepbookAdmin.d.mts +4 -4
- package/dist/transactions/marginAdmin.d.mts +7 -7
- package/dist/transactions/marginLiquidations.d.mts +3 -3
- package/dist/transactions/marginMaintainer.d.mts +5 -5
- package/dist/transactions/marginManager.d.mts +32 -32
- package/dist/transactions/marginPool.d.mts +18 -18
- package/dist/transactions/marginPool.d.mts.map +1 -1
- package/dist/transactions/marginRegistry.d.mts +16 -16
- package/dist/transactions/marginTPSL.d.mts +10 -10
- package/dist/transactions/marginTPSL.d.mts.map +1 -1
- package/dist/transactions/poolProxy.d.mts +8 -8
- package/dist/transactions/poolProxy.d.mts.map +1 -1
- package/package.json +2 -2
- package/src/contracts/deepbook_predict/expiry_market.ts +160 -0
- package/src/contracts/deepbook_predict/strike_exposure.ts +14 -0
- package/src/contracts/deepbook_sessions/sessions.ts +68 -0
- package/src/deployments/mainnet.ts +4 -1
- package/src/deployments/testnet.ts +6 -3
- package/src/deployments/types.ts +4 -2
- package/src/predict/client.ts +80 -27
- package/src/predict/config/generated.ts +4 -2
- package/src/predict/config/types.ts +3 -0
- package/src/predict/cost.ts +1022 -0
- package/src/predict/decode.ts +8 -8
- package/src/predict/index.ts +9 -0
- package/src/predict/reads/positions.ts +1 -1
- package/src/predict/tx/trade.ts +30 -1
- package/src/sessions.ts +37 -2
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/rolldown_runtime.mjs";
|
|
2
|
+
import { PredictInputError } from "./errors.mjs";
|
|
3
|
+
import { U64_MAX, fromRaw, usdcToRaw } from "./units.mjs";
|
|
4
|
+
import { POS_INF_TICK } from "./ticks.mjs";
|
|
5
|
+
import { upProbability } from "./pricing.mjs";
|
|
6
|
+
|
|
7
|
+
//#region src/predict/cost.ts
|
|
8
|
+
var cost_exports = /* @__PURE__ */ __exportAll({
|
|
9
|
+
BUILDER_FEE_MULTIPLIER: () => BUILDER_FEE_MULTIPLIER,
|
|
10
|
+
FEE_INCENTIVE_SUBSIDY_RATE: () => FEE_INCENTIVE_SUBSIDY_RATE,
|
|
11
|
+
FLOAT_SCALING: () => FLOAT_SCALING,
|
|
12
|
+
MAX_BUILDER_FEE_RATE: () => MAX_BUILDER_FEE_RATE,
|
|
13
|
+
MAX_QUANTITY_LOTS: () => MAX_QUANTITY_LOTS,
|
|
14
|
+
MIN_PREMIUM: () => MIN_PREMIUM,
|
|
15
|
+
POSITION_LOT_SIZE: () => POSITION_LOT_SIZE,
|
|
16
|
+
POS_INF_TICK: () => POS_INF_TICK,
|
|
17
|
+
SHIPPED_FEE_POLICY: () => SHIPPED_FEE_POLICY,
|
|
18
|
+
bernoulliFeeRate: () => bernoulliFeeRate,
|
|
19
|
+
boundaryProbabilities: () => boundaryProbabilities,
|
|
20
|
+
builderFee: () => builderFee,
|
|
21
|
+
closeInventoryImpact: () => closeInventoryImpact,
|
|
22
|
+
congestionPenaltyRate: () => congestionPenaltyRate,
|
|
23
|
+
decodeOrderRange: () => decodeOrderRange,
|
|
24
|
+
expiryFeeMultiplier: () => expiryFeeMultiplier,
|
|
25
|
+
feeIncentiveSubsidy: () => feeIncentiveSubsidy,
|
|
26
|
+
inventoryImpactPotential: () => inventoryImpactPotential,
|
|
27
|
+
mintCost: () => mintCost,
|
|
28
|
+
mintCostForBudget: () => mintCostForBudget,
|
|
29
|
+
mintInventoryImpact: () => mintInventoryImpact,
|
|
30
|
+
orderStrikes: () => orderStrikes,
|
|
31
|
+
rangeProbability: () => rangeProbability,
|
|
32
|
+
redeemLiveProceeds: () => redeemLiveProceeds,
|
|
33
|
+
sqrtDown: () => sqrtDown,
|
|
34
|
+
tradingFee: () => tradingFee
|
|
35
|
+
});
|
|
36
|
+
/** `math::float_scaling` — 1e9 is 1.0 for every rate and probability here. */
|
|
37
|
+
const FLOAT_SCALING = 1000000000n;
|
|
38
|
+
/** `constants::position_lot_size` — quantity is an integer number of these. */
|
|
39
|
+
const POSITION_LOT_SIZE = 10000n;
|
|
40
|
+
/** `constants::min_premium` — a mint below this premium aborts `EPremiumBelowMinimum`. */
|
|
41
|
+
const MIN_PREMIUM = 1000000n;
|
|
42
|
+
/** `constants::builder_fee_multiplier` — the builder's cut of the trading fee (10%). */
|
|
43
|
+
const BUILDER_FEE_MULTIPLIER = 100000000n;
|
|
44
|
+
/** `constants::max_builder_fee_rate` — cap on the builder fee as a share of quantity (0.5%). */
|
|
45
|
+
const MAX_BUILDER_FEE_RATE = 5000000n;
|
|
46
|
+
/** `constants::fee_incentive_subsidy_rate` — sponsor share of a trader's mint fee (20%). */
|
|
47
|
+
const FEE_INCENTIVE_SUBSIDY_RATE = 200000000n;
|
|
48
|
+
/** `order::max_quantity_lots` — the order ID's 32-bit lot field. */
|
|
49
|
+
const MAX_QUANTITY_LOTS = (1n << 32n) - 1n;
|
|
50
|
+
const mulDown = (x, y) => x * y / FLOAT_SCALING;
|
|
51
|
+
const divDown = (x, y) => x * FLOAT_SCALING / y;
|
|
52
|
+
const mulDivDown = (x, y, denominator) => x * y / denominator;
|
|
53
|
+
const min = (a, b) => a < b ? a : b;
|
|
54
|
+
const max = (a, b) => a > b ? a : b;
|
|
55
|
+
function assertUint(value, name, maximum = U64_MAX, minimum = 0n) {
|
|
56
|
+
if (typeof value !== "bigint" || value < minimum || value > maximum) throw new PredictInputError(`${name} must be an integer in [${minimum}, ${maximum}], got ${value}`);
|
|
57
|
+
}
|
|
58
|
+
function sqrtInitialGuess(x) {
|
|
59
|
+
let bits = 0n;
|
|
60
|
+
let val = x;
|
|
61
|
+
if (val >= 1n << 64n) {
|
|
62
|
+
val >>= 64n;
|
|
63
|
+
bits += 64n;
|
|
64
|
+
}
|
|
65
|
+
if (val >= 1n << 32n) {
|
|
66
|
+
val >>= 32n;
|
|
67
|
+
bits += 32n;
|
|
68
|
+
}
|
|
69
|
+
if (val >= 1n << 16n) {
|
|
70
|
+
val >>= 16n;
|
|
71
|
+
bits += 16n;
|
|
72
|
+
}
|
|
73
|
+
if (val >= 1n << 8n) {
|
|
74
|
+
val >>= 8n;
|
|
75
|
+
bits += 8n;
|
|
76
|
+
}
|
|
77
|
+
if (val >= 1n << 4n) {
|
|
78
|
+
val >>= 4n;
|
|
79
|
+
bits += 4n;
|
|
80
|
+
}
|
|
81
|
+
if (val >= 1n << 2n) {
|
|
82
|
+
val >>= 2n;
|
|
83
|
+
bits += 2n;
|
|
84
|
+
}
|
|
85
|
+
if (val >= 1n << 1n) bits += 1n;
|
|
86
|
+
return 1n << (bits + 1n) / 2n;
|
|
87
|
+
}
|
|
88
|
+
function sqrtU128Down(x) {
|
|
89
|
+
if (x === 0n) return 0n;
|
|
90
|
+
if (x < 4n) return 1n;
|
|
91
|
+
let g = sqrtInitialGuess(x);
|
|
92
|
+
for (let i = 0; i < 7; i++) g = (g + x / g) / 2n;
|
|
93
|
+
if (g > x / g) g -= 1n;
|
|
94
|
+
return g;
|
|
95
|
+
}
|
|
96
|
+
/** `math::sqrt_down` — square root of a 1e9-scaled value, 1e9-scaled, rounded down. */
|
|
97
|
+
function sqrtDown(x) {
|
|
98
|
+
assertUint(x, "sqrt input");
|
|
99
|
+
return sqrtU128Down(x * FLOAT_SCALING);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The shipped template (`config_constants` defaults): 10% Bernoulli fee, a 2.2% per-leg floor,
|
|
103
|
+
* a one-day ramp window that is inert at a 1.0 multiplier, a 1%–99% entry band, and inventory
|
|
104
|
+
* impact disabled. A market that was created under these values charges exactly this; one
|
|
105
|
+
* created after an admin change does not, which is why the per-market snapshot is the real
|
|
106
|
+
* answer. Verify against the deployment's `MarketCreated` before pricing money on it.
|
|
107
|
+
*/
|
|
108
|
+
const SHIPPED_FEE_POLICY = Object.freeze({
|
|
109
|
+
baseFee: 100000000n,
|
|
110
|
+
minFee: 22000000n,
|
|
111
|
+
expiryFeeWindowMs: 86400000n,
|
|
112
|
+
expiryFeeMaxMultiplier: FLOAT_SCALING,
|
|
113
|
+
minEntryProbability: 10000000n,
|
|
114
|
+
maxEntryProbability: 990000000n,
|
|
115
|
+
inventoryImpactMaxRate: 0n,
|
|
116
|
+
inventoryImpactScale: 0n,
|
|
117
|
+
backingBufferLambda: 310000000n
|
|
118
|
+
});
|
|
119
|
+
function assertFeePolicy(policy) {
|
|
120
|
+
assertUint(policy.baseFee, "baseFee", FLOAT_SCALING);
|
|
121
|
+
assertUint(policy.minFee, "minFee", FLOAT_SCALING);
|
|
122
|
+
assertUint(policy.expiryFeeWindowMs, "expiryFeeWindowMs", U64_MAX, 1n);
|
|
123
|
+
assertUint(policy.expiryFeeMaxMultiplier, "expiryFeeMaxMultiplier", 10n * FLOAT_SCALING, FLOAT_SCALING);
|
|
124
|
+
assertUint(policy.minEntryProbability, "minEntryProbability", FLOAT_SCALING);
|
|
125
|
+
assertUint(policy.maxEntryProbability, "maxEntryProbability", FLOAT_SCALING);
|
|
126
|
+
if (policy.minEntryProbability >= policy.maxEntryProbability) throw new PredictInputError("minEntryProbability must be below maxEntryProbability");
|
|
127
|
+
assertUint(policy.inventoryImpactMaxRate, "inventoryImpactMaxRate", FLOAT_SCALING);
|
|
128
|
+
assertUint(policy.backingBufferLambda, "backingBufferLambda", FLOAT_SCALING);
|
|
129
|
+
assertUint(policy.inventoryImpactScale, "inventoryImpactScale", U64_MAX, policy.inventoryImpactMaxRate === 0n ? 0n : 1n);
|
|
130
|
+
}
|
|
131
|
+
function assertBoundaries(boundaries) {
|
|
132
|
+
if (boundaries.lowerUp !== null) assertUint(boundaries.lowerUp, "lowerUp", FLOAT_SCALING);
|
|
133
|
+
if (boundaries.higherUp !== null) assertUint(boundaries.higherUp, "higherUp", FLOAT_SCALING);
|
|
134
|
+
}
|
|
135
|
+
function assertBook(book) {
|
|
136
|
+
assertUint(book.totalPayout, "totalPayout");
|
|
137
|
+
assertUint(book.maxPayout, "maxPayout", book.totalPayout);
|
|
138
|
+
assertUint(book.rangeMaxPayout, "rangeMaxPayout", book.maxPayout);
|
|
139
|
+
}
|
|
140
|
+
function assertCostInputs(inputs) {
|
|
141
|
+
assertFeePolicy(inputs.fees);
|
|
142
|
+
assertUint(inputs.penaltyRate ?? 0n, "penaltyRate", FLOAT_SCALING);
|
|
143
|
+
assertUint(inputs.lotSize ?? POSITION_LOT_SIZE, "lotSize", U64_MAX / MAX_QUANTITY_LOTS, 1n);
|
|
144
|
+
if (inputs.fees.inventoryImpactMaxRate > 0n && !inputs.book) throw new PredictInputError("book is required when inventory impact is enabled");
|
|
145
|
+
if (inputs.book) assertBook(inputs.book);
|
|
146
|
+
}
|
|
147
|
+
/** `strike_exposure_config::raw_bernoulli_fee_rate` — `base_fee · sqrt(p·(1−p))`, the fee rate
|
|
148
|
+
* before the `min_fee` floor and the expiry ramp. Zero at the certain ends. */
|
|
149
|
+
function bernoulliFeeRate(baseFee, probability) {
|
|
150
|
+
assertUint(baseFee, "baseFee", FLOAT_SCALING);
|
|
151
|
+
assertUint(probability, "probability (EInvalidFeeProbability)", FLOAT_SCALING);
|
|
152
|
+
if (probability === 0n || probability === FLOAT_SCALING) return 0n;
|
|
153
|
+
return mulDown(baseFee, sqrtDown(mulDown(probability, FLOAT_SCALING - probability)));
|
|
154
|
+
}
|
|
155
|
+
/** `strike_exposure_config::expiry_fee_multiplier` — 1.0 outside the window, rising linearly
|
|
156
|
+
* to `expiry_fee_max_multiplier` at expiry. */
|
|
157
|
+
function expiryFeeMultiplier(policy, timeToExpiryMs) {
|
|
158
|
+
assertFeePolicy(policy);
|
|
159
|
+
assertUint(timeToExpiryMs, "timeToExpiryMs");
|
|
160
|
+
if (timeToExpiryMs >= policy.expiryFeeWindowMs) return FLOAT_SCALING;
|
|
161
|
+
return FLOAT_SCALING + mulDivDown(policy.expiryFeeMaxMultiplier - FLOAT_SCALING, policy.expiryFeeWindowMs - timeToExpiryMs, policy.expiryFeeWindowMs);
|
|
162
|
+
}
|
|
163
|
+
function legTradingFee(policy, probability, quantity, timeToExpiryMs) {
|
|
164
|
+
return mulDown(mulDown(max(bernoulliFeeRate(policy.baseFee, probability), policy.minFee), expiryFeeMultiplier(policy, timeToExpiryMs)), quantity);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* `strike_exposure_config::trading_fee` — the fee for a whole range, charged PER FINITE
|
|
168
|
+
* BOUNDARY with each leg floored and ramped independently. A binary order has one finite
|
|
169
|
+
* boundary and pays one leg; a two-sided range pays two, so it is not the same fee as the
|
|
170
|
+
* range's own probability would suggest.
|
|
171
|
+
*/
|
|
172
|
+
function tradingFee(policy, boundaries, quantity, timeToExpiryMs) {
|
|
173
|
+
assertFeePolicy(policy);
|
|
174
|
+
assertBoundaries(boundaries);
|
|
175
|
+
assertUint(quantity, "quantity");
|
|
176
|
+
assertUint(timeToExpiryMs, "timeToExpiryMs");
|
|
177
|
+
return (boundaries.lowerUp === null ? 0n : legTradingFee(policy, boundaries.lowerUp, quantity, timeToExpiryMs)) + (boundaries.higherUp === null ? 0n : legTradingFee(policy, boundaries.higherUp, quantity, timeToExpiryMs));
|
|
178
|
+
}
|
|
179
|
+
/** `expiry_market::builder_fee_amount` — an account carrying a builder code pays the builder a
|
|
180
|
+
* multiple of its trading fee, capped as a share of quantity. */
|
|
181
|
+
function builderFee(fee, quantity, hasBuilderCode) {
|
|
182
|
+
assertUint(fee, "fee");
|
|
183
|
+
assertUint(quantity, "quantity");
|
|
184
|
+
if (!hasBuilderCode) return 0n;
|
|
185
|
+
return min(mulDown(fee, BUILDER_FEE_MULTIPLIER), mulDown(quantity, MAX_BUILDER_FEE_RATE));
|
|
186
|
+
}
|
|
187
|
+
/** `expiry_market::fee_incentive_subsidy_amount` — a sponsor pays part of the trader's MINT
|
|
188
|
+
* fee, bounded by the expiry's remaining sponsored balance. Mints only; redeems pay in full. */
|
|
189
|
+
function feeIncentiveSubsidy(fee, feeIncentiveBalance) {
|
|
190
|
+
assertUint(fee, "fee");
|
|
191
|
+
assertUint(feeIncentiveBalance, "feeIncentiveBalance");
|
|
192
|
+
return min(mulDown(fee, FEE_INCENTIVE_SUBSIDY_RATE), feeIncentiveBalance);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* `ewma::penalty_fee`'s firing test, as a per-unit RATE: `penalty_rate` when the transaction's
|
|
196
|
+
* gas price is a high outlier against the market's pre-trade EWMA, else zero. It is a rate and
|
|
197
|
+
* not an amount because the surcharge is `rate · quantity`, and a budget search has to reprice
|
|
198
|
+
* it at every candidate quantity. `gasPrice` is the raw reference gas price (not 1e9-scaled),
|
|
199
|
+
* as `tx_context::gas_price` reports it.
|
|
200
|
+
*/
|
|
201
|
+
function congestionPenaltyRate(policy, state, gasPrice) {
|
|
202
|
+
assertUint(policy.penaltyRate, "penaltyRate", FLOAT_SCALING);
|
|
203
|
+
assertUint(policy.zScoreThreshold, "zScoreThreshold");
|
|
204
|
+
assertUint(state.mean, "mean");
|
|
205
|
+
assertUint(state.variance, "variance");
|
|
206
|
+
assertUint(gasPrice, "gasPrice", U64_MAX / FLOAT_SCALING);
|
|
207
|
+
if (!policy.enabled || state.variance === 0n) return 0n;
|
|
208
|
+
const scaled = gasPrice * FLOAT_SCALING;
|
|
209
|
+
if (scaled <= state.mean) return 0n;
|
|
210
|
+
if (divDown(scaled - state.mean, sqrtDown(state.variance)) <= policy.zScoreThreshold) return 0n;
|
|
211
|
+
return policy.penaltyRate;
|
|
212
|
+
}
|
|
213
|
+
function payoutLiability(policy, maxPayout, totalPayout) {
|
|
214
|
+
return maxPayout + mulDown(policy.backingBufferLambda, totalPayout - maxPayout);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* `strike_exposure::inventory_impact_potential_for_liability` — the book-level potential
|
|
218
|
+
* `phi(L)`: marginal rate rising linearly to `inventory_impact_max_rate` over the scale `B`,
|
|
219
|
+
* flat at the cap above it. Trades are charged the DIFFERENCE of two evaluations, which is
|
|
220
|
+
* what makes inventory cycles telescope to zero.
|
|
221
|
+
*/
|
|
222
|
+
function inventoryImpactPotential(policy, liability) {
|
|
223
|
+
assertFeePolicy(policy);
|
|
224
|
+
assertUint(liability, "liability");
|
|
225
|
+
if (policy.inventoryImpactMaxRate === 0n || liability === 0n) return 0n;
|
|
226
|
+
const scale = policy.inventoryImpactScale;
|
|
227
|
+
const capped = min(liability, scale);
|
|
228
|
+
const utilization = mulDivDown(capped, FLOAT_SCALING, scale);
|
|
229
|
+
const potentialAtCapped = mulDown(mulDown(policy.inventoryImpactMaxRate, utilization), capped) / 2n;
|
|
230
|
+
if (liability <= scale) return potentialAtCapped;
|
|
231
|
+
return potentialAtCapped + mulDown(policy.inventoryImpactMaxRate, liability - scale);
|
|
232
|
+
}
|
|
233
|
+
/** `strike_exposure::mint_range_inventory_impact` — the charge a mint of `quantity` over a
|
|
234
|
+
* range pays: the exact rise in the book potential. Zero at the shipped rate of `0n`. */
|
|
235
|
+
function mintInventoryImpact(policy, book, quantity) {
|
|
236
|
+
assertFeePolicy(policy);
|
|
237
|
+
assertBook(book);
|
|
238
|
+
assertUint(quantity, "quantity", U64_MAX - book.totalPayout);
|
|
239
|
+
if (policy.inventoryImpactMaxRate === 0n || quantity === 0n) return 0n;
|
|
240
|
+
const before = payoutLiability(policy, book.maxPayout, book.totalPayout);
|
|
241
|
+
return inventoryImpactPotential(policy, payoutLiability(policy, max(book.maxPayout, book.rangeMaxPayout + quantity), book.totalPayout + quantity)) - inventoryImpactPotential(policy, before);
|
|
242
|
+
}
|
|
243
|
+
/** `strike_exposure::live_close_inventory_impact` — the rebate a live close of `payout`
|
|
244
|
+
* receives: the exact fall in the same potential. Zero at the shipped rate of `0n`. */
|
|
245
|
+
function closeInventoryImpact(policy, book, payout) {
|
|
246
|
+
assertFeePolicy(policy);
|
|
247
|
+
assertBook(book);
|
|
248
|
+
assertUint(book.complementMaxPayout, "complementMaxPayout", book.maxPayout);
|
|
249
|
+
if (max(book.rangeMaxPayout, book.complementMaxPayout) !== book.maxPayout) throw new PredictInputError("maxPayout must equal the larger range or complement payout");
|
|
250
|
+
assertUint(payout, "close payout", book.rangeMaxPayout);
|
|
251
|
+
if (policy.inventoryImpactMaxRate === 0n || payout === 0n) return 0n;
|
|
252
|
+
const before = payoutLiability(policy, book.maxPayout, book.totalPayout);
|
|
253
|
+
const after = payoutLiability(policy, max(book.rangeMaxPayout - payout, book.complementMaxPayout), book.totalPayout - payout);
|
|
254
|
+
return inventoryImpactPotential(policy, before) - inventoryImpactPotential(policy, after);
|
|
255
|
+
}
|
|
256
|
+
/** `pricing::probability` — the range's own probability, `up(lower) − up(higher)` with the
|
|
257
|
+
* chain's saturating subtraction and its infinite-boundary defaults. */
|
|
258
|
+
function rangeProbability(boundaries) {
|
|
259
|
+
assertBoundaries(boundaries);
|
|
260
|
+
const lower = boundaries.lowerUp ?? FLOAT_SCALING;
|
|
261
|
+
const higher = boundaries.higherUp ?? 0n;
|
|
262
|
+
return lower > higher ? lower - higher : 0n;
|
|
263
|
+
}
|
|
264
|
+
function toRawProbability(p) {
|
|
265
|
+
if (!Number.isFinite(p)) throw new PredictInputError(`probability is not finite: ${p}`);
|
|
266
|
+
const raw = BigInt(Math.round(p * Number(FLOAT_SCALING)));
|
|
267
|
+
return raw < 0n ? 0n : raw > FLOAT_SCALING ? FLOAT_SCALING : raw;
|
|
268
|
+
}
|
|
269
|
+
/** Price a range's two boundaries with the local float pricer. `lower`/`upper` are strikes in
|
|
270
|
+
* USD; pass `null` for an infinite side (`{ lower: strike, upper: null }` is an UP order,
|
|
271
|
+
* `{ lower: null, upper: strike }` a DOWN order). Carries the pricer's ~1e-4 approximation. */
|
|
272
|
+
function boundaryProbabilities(pricer, lower, upper) {
|
|
273
|
+
return {
|
|
274
|
+
lowerUp: lower === null ? null : toRawProbability(upProbability(pricer, lower)),
|
|
275
|
+
higherUp: upper === null ? null : toRawProbability(upProbability(pricer, upper))
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function resolveBoundaries(source) {
|
|
279
|
+
let boundaries;
|
|
280
|
+
let exact;
|
|
281
|
+
if ("pricer" in source) {
|
|
282
|
+
const { lower, upper } = source;
|
|
283
|
+
if (lower !== null && upper !== null && lower >= upper) throw new PredictInputError(`lower strike ${lower} must be below ${upper} (EInvalidRange)`);
|
|
284
|
+
boundaries = boundaryProbabilities(source.pricer, lower, upper);
|
|
285
|
+
exact = false;
|
|
286
|
+
} else {
|
|
287
|
+
boundaries = source;
|
|
288
|
+
exact = true;
|
|
289
|
+
}
|
|
290
|
+
assertBoundaries(boundaries);
|
|
291
|
+
if (boundaries.lowerUp === null && boundaries.higherUp === null) throw new PredictInputError("a range cannot be infinite on both sides (EInvalidRange)");
|
|
292
|
+
return {
|
|
293
|
+
boundaries,
|
|
294
|
+
exact
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function rawAmount(value) {
|
|
298
|
+
const raw = typeof value === "bigint" ? value : usdcToRaw(value);
|
|
299
|
+
assertUint(raw, "amount");
|
|
300
|
+
return raw;
|
|
301
|
+
}
|
|
302
|
+
function rawMs(value) {
|
|
303
|
+
if (typeof value === "number" && !Number.isSafeInteger(value)) throw new PredictInputError(`timestamp must be a safe integer in milliseconds, got ${value}`);
|
|
304
|
+
const raw = typeof value === "bigint" ? value : BigInt(value);
|
|
305
|
+
assertUint(raw, "timestamp");
|
|
306
|
+
return raw;
|
|
307
|
+
}
|
|
308
|
+
function assertProbabilityPolicy(policy, probability) {
|
|
309
|
+
if (probability < policy.minEntryProbability || probability > policy.maxEntryProbability) throw new PredictInputError(`entry probability ${probability} outside the market's [${policy.minEntryProbability}, ${policy.maxEntryProbability}] admission band (EEntryProbabilityOutOfBounds)`);
|
|
310
|
+
}
|
|
311
|
+
function assertRangeMintPolicy(policy, boundaries) {
|
|
312
|
+
if (boundaries.lowerUp !== null) assertProbabilityPolicy(policy, boundaries.lowerUp);
|
|
313
|
+
if (boundaries.higherUp !== null) assertProbabilityPolicy(policy, FLOAT_SCALING - boundaries.higherUp);
|
|
314
|
+
assertProbabilityPolicy(policy, rangeProbability(boundaries));
|
|
315
|
+
}
|
|
316
|
+
function assertValidQuantity(quantity, lotSize) {
|
|
317
|
+
if (quantity <= 0n || quantity % lotSize !== 0n || quantity / lotSize > MAX_QUANTITY_LOTS) throw new PredictInputError(`quantity ${quantity} must be a positive multiple of the ${lotSize} lot size, at most ${MAX_QUANTITY_LOTS} lots (EInvalidQuantity)`);
|
|
318
|
+
}
|
|
319
|
+
function timeToExpiry(expiryMs, nowMs) {
|
|
320
|
+
if (nowMs >= expiryMs) throw new PredictInputError(`market expired at ${expiryMs}; a live trade at ${nowMs} aborts (ELivePricingExpired)`);
|
|
321
|
+
return expiryMs - nowMs;
|
|
322
|
+
}
|
|
323
|
+
function mintQuoteAt(inputs, boundaries, quantity, timeToExpiryMs) {
|
|
324
|
+
const premium = mulDown(rangeProbability(boundaries), quantity);
|
|
325
|
+
const fee = tradingFee(inputs.fees, boundaries, quantity, timeToExpiryMs);
|
|
326
|
+
const subsidy = feeIncentiveSubsidy(fee, rawAmount(inputs.feeIncentiveBalance ?? 0n));
|
|
327
|
+
const builder = builderFee(fee, quantity, inputs.builderCode ?? false);
|
|
328
|
+
const penalty = mulDown(inputs.penaltyRate ?? 0n, quantity);
|
|
329
|
+
const impact = inputs.book ? mintInventoryImpact(inputs.fees, inputs.book, quantity) : 0n;
|
|
330
|
+
return {
|
|
331
|
+
premium,
|
|
332
|
+
fee,
|
|
333
|
+
subsidy,
|
|
334
|
+
builder,
|
|
335
|
+
penalty,
|
|
336
|
+
impact,
|
|
337
|
+
cost: premium + (fee - subsidy) + builder + penalty + impact
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function mintCostFrom(inputs, boundaries, exact, quantity, timeToExpiryMs) {
|
|
341
|
+
const q = mintQuoteAt(inputs, boundaries, quantity, timeToExpiryMs);
|
|
342
|
+
const probability = rangeProbability(boundaries);
|
|
343
|
+
return {
|
|
344
|
+
quantity: fromRaw(quantity, 6),
|
|
345
|
+
entryProbability: fromRaw(probability, 9),
|
|
346
|
+
premium: fromRaw(q.premium, 6),
|
|
347
|
+
fees: {
|
|
348
|
+
trading: fromRaw(q.fee, 6),
|
|
349
|
+
subsidy: fromRaw(q.subsidy, 6),
|
|
350
|
+
builder: fromRaw(q.builder, 6),
|
|
351
|
+
penalty: fromRaw(q.penalty, 6),
|
|
352
|
+
impact: fromRaw(q.impact, 6)
|
|
353
|
+
},
|
|
354
|
+
cost: fromRaw(q.cost, 6),
|
|
355
|
+
costPerContract: quantity === 0n ? 0 : Number(q.cost) / Number(quantity),
|
|
356
|
+
payoutMultiple: Number(quantity) / Number(q.cost),
|
|
357
|
+
raw: {
|
|
358
|
+
quantity,
|
|
359
|
+
entryProbability: probability,
|
|
360
|
+
premium: q.premium,
|
|
361
|
+
tradingFee: q.fee,
|
|
362
|
+
subsidy: q.subsidy,
|
|
363
|
+
builderFee: q.builder,
|
|
364
|
+
penaltyFee: q.penalty,
|
|
365
|
+
impactCharge: q.impact,
|
|
366
|
+
cost: q.cost
|
|
367
|
+
},
|
|
368
|
+
exactProbabilities: exact
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* All-in cost of minting an exact payout quantity — the `mint_exact_quantity` shape, priced
|
|
373
|
+
* entirely client-side. Mirrors `compute_mint_quote`, including its admission checks: the
|
|
374
|
+
* entry-probability band on each finite leg and on the range, the `min_premium` floor, the lot
|
|
375
|
+
* grid, and the `all_in_cost <= quantity` bound (a contract may never cost more than it can
|
|
376
|
+
* pay out). Each violation throws the `PredictInputError` naming the abort the chain would
|
|
377
|
+
* have raised.
|
|
378
|
+
*/
|
|
379
|
+
function mintCost(inputs) {
|
|
380
|
+
assertCostInputs(inputs);
|
|
381
|
+
const { boundaries, exact } = resolveBoundaries(inputs.probabilities);
|
|
382
|
+
const lotSize = inputs.lotSize ?? POSITION_LOT_SIZE;
|
|
383
|
+
const quantity = rawAmount(inputs.quantity);
|
|
384
|
+
const ttl = timeToExpiry(rawMs(inputs.expiryMs), rawMs(inputs.nowMs ?? Date.now()));
|
|
385
|
+
assertRangeMintPolicy(inputs.fees, boundaries);
|
|
386
|
+
const premium = mulDown(rangeProbability(boundaries), quantity);
|
|
387
|
+
if (premium < MIN_PREMIUM) throw new PredictInputError(`premium ${premium} is below the ${MIN_PREMIUM} minimum (EPremiumBelowMinimum)`);
|
|
388
|
+
assertValidQuantity(quantity, lotSize);
|
|
389
|
+
const quote = mintCostFrom(inputs, boundaries, exact, quantity, ttl);
|
|
390
|
+
if (quote.raw.cost > quantity) throw new PredictInputError(`all-in cost ${quote.raw.cost} exceeds the maximum payout ${quantity} (EMintCostAboveMaxPayout)`);
|
|
391
|
+
return quote;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* A fill whose ALL-IN cost fits a budget — `expiry_market::mint_exact_cost` computed
|
|
395
|
+
* client-side, with the same lot search over the same cost function, so the answer is the
|
|
396
|
+
* quantity that entrypoint would size and the cost it would debit.
|
|
397
|
+
*
|
|
398
|
+
* Without it a "spend exactly $X" flow has to guess: every fee is charged ON TOP of the
|
|
399
|
+
* premium, so the caller subtracts an estimated fee load, pads it against an abort, and
|
|
400
|
+
* systematically underspends. Here the whole search runs locally; submit the all-in budget
|
|
401
|
+
* through `tx.mintCost` on deployments carrying `mint_exact_cost`.
|
|
402
|
+
*
|
|
403
|
+
* Sizing also respects the fill's maximum payout and the 32-bit lot cap; either can leave
|
|
404
|
+
* substantial budget unspent. When only the budget binds, one more lot would exceed it.
|
|
405
|
+
* If the budget fill exceeds its maximum payout, the contract's step-down is best effort:
|
|
406
|
+
* rounding can make it miss a larger admissible fill, including one meeting `minQuantity`.
|
|
407
|
+
* The chain caps the budget at the account balance first ({@link MintBudgetInputs.accountBalance}).
|
|
408
|
+
*/
|
|
409
|
+
function mintCostForBudget(inputs) {
|
|
410
|
+
assertCostInputs(inputs);
|
|
411
|
+
const { boundaries, exact } = resolveBoundaries(inputs.probabilities);
|
|
412
|
+
const lotSize = inputs.lotSize ?? POSITION_LOT_SIZE;
|
|
413
|
+
const ttl = timeToExpiry(rawMs(inputs.expiryMs), rawMs(inputs.nowMs ?? Date.now()));
|
|
414
|
+
const minQuantity = inputs.minQuantity === void 0 ? lotSize : rawAmount(inputs.minQuantity);
|
|
415
|
+
const requestedBudget = rawAmount(inputs.budget);
|
|
416
|
+
let budget = requestedBudget;
|
|
417
|
+
if (inputs.accountBalance !== void 0) budget = min(budget, rawAmount(inputs.accountBalance));
|
|
418
|
+
assertRangeMintPolicy(inputs.fees, boundaries);
|
|
419
|
+
const probability = rangeProbability(boundaries);
|
|
420
|
+
let lo = 0n;
|
|
421
|
+
let hi = MAX_QUANTITY_LOTS;
|
|
422
|
+
while (lo < hi) {
|
|
423
|
+
const mid = (lo + hi + 1n) / 2n;
|
|
424
|
+
if (mulDown(probability, mid * lotSize) <= budget) lo = mid;
|
|
425
|
+
else hi = mid - 1n;
|
|
426
|
+
}
|
|
427
|
+
const allInCostAt = (quantity$1) => mintQuoteAt(inputs, boundaries, quantity$1, ttl).cost;
|
|
428
|
+
hi = lo;
|
|
429
|
+
lo = 0n;
|
|
430
|
+
while (lo < hi) {
|
|
431
|
+
const mid = (lo + hi + 1n) / 2n;
|
|
432
|
+
if (allInCostAt(mid * lotSize) <= budget) lo = mid;
|
|
433
|
+
else hi = mid - 1n;
|
|
434
|
+
}
|
|
435
|
+
const budgetLots = lo;
|
|
436
|
+
const budgetQuantity = budgetLots * lotSize;
|
|
437
|
+
let lots = budgetLots;
|
|
438
|
+
if (budgetLots > 0n && allInCostAt(budgetQuantity) > budgetQuantity) {
|
|
439
|
+
let stepLo = 0n;
|
|
440
|
+
let stepHi = budgetLots - 1n;
|
|
441
|
+
while (stepLo < stepHi) {
|
|
442
|
+
const mid = (stepLo + stepHi + 1n) / 2n;
|
|
443
|
+
const candidate = mid * lotSize;
|
|
444
|
+
if (allInCostAt(candidate) <= candidate) stepLo = mid;
|
|
445
|
+
else stepHi = mid - 1n;
|
|
446
|
+
}
|
|
447
|
+
lots = stepLo === 0n ? budgetLots : stepLo;
|
|
448
|
+
}
|
|
449
|
+
const quantity = lots * lotSize;
|
|
450
|
+
if (quantity < minQuantity) throw new PredictInputError(`budget ${budget} sizes ${quantity}, below the ${minQuantity} minimum (EMintQuantityBelowMin)`);
|
|
451
|
+
const premium = mulDown(probability, quantity);
|
|
452
|
+
if (premium < MIN_PREMIUM) throw new PredictInputError(`budget ${budget} sizes a premium of ${premium}, below the ${MIN_PREMIUM} minimum (EPremiumBelowMinimum)`);
|
|
453
|
+
assertValidQuantity(quantity, lotSize);
|
|
454
|
+
const quote = mintCostFrom(inputs, boundaries, exact, quantity, ttl);
|
|
455
|
+
if (quote.raw.cost > quantity) throw new PredictInputError(`sized fill inside budget ${budget} costs more than it can pay out: ${quote.raw.cost} exceeds ${quantity} (EMintCostAboveMaxPayout)`);
|
|
456
|
+
return {
|
|
457
|
+
...quote,
|
|
458
|
+
budget: fromRaw(requestedBudget, 6),
|
|
459
|
+
effectiveBudget: fromRaw(budget, 6),
|
|
460
|
+
unspentBudget: fromRaw(requestedBudget - quote.raw.cost, 6),
|
|
461
|
+
raw: {
|
|
462
|
+
...quote.raw,
|
|
463
|
+
budget: requestedBudget,
|
|
464
|
+
effectiveBudget: budget,
|
|
465
|
+
unspentBudget: requestedBudget - quote.raw.cost
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Net proceeds of closing a live position — `expiry_market::redeem_live`'s payment
|
|
471
|
+
* decomposition, client-side. The mirror of {@link mintCost}: the same per-boundary trading
|
|
472
|
+
* fee and builder fee, the same congestion surcharge, and the inventory-impact term as a
|
|
473
|
+
* REBATE rather than a charge. There is no sponsor subsidy on a close (incentives subsidise
|
|
474
|
+
* mints only), and each deduction is clamped at the payout remaining after the ones before it,
|
|
475
|
+
* exactly as the contract clamps them, so a close can never cost more than it releases.
|
|
476
|
+
*
|
|
477
|
+
* Use this for a local UI preview from a supplied snapshot. `read.quoteRedeem` simulates
|
|
478
|
+
* the actual close and remains the pre-trade check for ownership, remaining position size,
|
|
479
|
+
* live-market gates and current fees. `proceeds` is what `min_proceeds` is compared against
|
|
480
|
+
* on the real call; this preview does not guarantee execution at that amount.
|
|
481
|
+
*/
|
|
482
|
+
function redeemLiveProceeds(inputs) {
|
|
483
|
+
assertCostInputs(inputs);
|
|
484
|
+
const { boundaries, exact } = resolveBoundaries(inputs.probabilities);
|
|
485
|
+
const lotSize = inputs.lotSize ?? POSITION_LOT_SIZE;
|
|
486
|
+
const quantity = rawAmount(inputs.closeQuantity);
|
|
487
|
+
const ttl = timeToExpiry(rawMs(inputs.expiryMs), rawMs(inputs.nowMs ?? Date.now()));
|
|
488
|
+
assertValidQuantity(quantity, lotSize);
|
|
489
|
+
const positionQuantity = inputs.positionQuantity === void 0 ? null : rawAmount(inputs.positionQuantity);
|
|
490
|
+
if (positionQuantity !== null) {
|
|
491
|
+
assertValidQuantity(positionQuantity, lotSize);
|
|
492
|
+
if (quantity > positionQuantity) throw new PredictInputError("closeQuantity exceeds positionQuantity");
|
|
493
|
+
}
|
|
494
|
+
const remainingQuantity = positionQuantity === null ? null : positionQuantity - quantity;
|
|
495
|
+
const probability = rangeProbability(boundaries);
|
|
496
|
+
const gross = mulDown(probability, quantity);
|
|
497
|
+
const fee = min(tradingFee(inputs.fees, boundaries, quantity, ttl), gross);
|
|
498
|
+
const builder = min(builderFee(fee, quantity, inputs.builderCode ?? false), gross - fee);
|
|
499
|
+
const penalty = min(mulDown(inputs.penaltyRate ?? 0n, quantity), gross - fee - builder);
|
|
500
|
+
const rebate = inputs.book ? closeInventoryImpact(inputs.fees, inputs.book, quantity) : 0n;
|
|
501
|
+
const proceeds = gross + rebate - fee - builder - penalty;
|
|
502
|
+
return {
|
|
503
|
+
proceeds: fromRaw(proceeds, 6),
|
|
504
|
+
gross: fromRaw(gross, 6),
|
|
505
|
+
fees: {
|
|
506
|
+
trading: fromRaw(fee, 6),
|
|
507
|
+
builder: fromRaw(builder, 6),
|
|
508
|
+
penalty: fromRaw(penalty, 6),
|
|
509
|
+
impactRebate: fromRaw(rebate, 6)
|
|
510
|
+
},
|
|
511
|
+
quantityClosed: fromRaw(quantity, 6),
|
|
512
|
+
remainingQuantity: remainingQuantity === null ? null : fromRaw(remainingQuantity, 6),
|
|
513
|
+
proceedsPerContract: Number(proceeds) / Number(quantity),
|
|
514
|
+
probability: fromRaw(probability, 9),
|
|
515
|
+
raw: {
|
|
516
|
+
proceeds,
|
|
517
|
+
gross,
|
|
518
|
+
tradingFee: fee,
|
|
519
|
+
builderFee: builder,
|
|
520
|
+
penaltyFee: penalty,
|
|
521
|
+
impactRebate: rebate,
|
|
522
|
+
quantityClosed: quantity,
|
|
523
|
+
remainingQuantity,
|
|
524
|
+
probability
|
|
525
|
+
},
|
|
526
|
+
exactProbabilities: exact
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
const QUANTITY_LOTS_OFFSET = 100n;
|
|
530
|
+
const LOWER_TICK_OFFSET = 70n;
|
|
531
|
+
const HIGHER_TICK_OFFSET = 40n;
|
|
532
|
+
const TICK_MASK = POS_INF_TICK;
|
|
533
|
+
const U32_MASK = (1n << 32n) - 1n;
|
|
534
|
+
/** Decode an order ID's range and quantity — the TypeScript mirror of `order::lower_tick` /
|
|
535
|
+
* `higher_tick` / `quantity`. */
|
|
536
|
+
function decodeOrderRange(orderId, lotSize = POSITION_LOT_SIZE) {
|
|
537
|
+
return {
|
|
538
|
+
lowerTick: orderId >> LOWER_TICK_OFFSET & TICK_MASK,
|
|
539
|
+
higherTick: orderId >> HIGHER_TICK_OFFSET & TICK_MASK,
|
|
540
|
+
quantity: (orderId >> QUANTITY_LOTS_OFFSET & U32_MASK) * lotSize
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
/** The strikes an {@link OrderRange} prices against, in USD, with `null` for each infinite
|
|
544
|
+
* side — the shape {@link boundaryProbabilities} takes. `tickSize` is the market's raw tick
|
|
545
|
+
* size (`ActiveMarket.tickSize` in USD, or the raw value from the deployment). */
|
|
546
|
+
function orderStrikes(range, tickSizeRaw) {
|
|
547
|
+
return {
|
|
548
|
+
lower: range.lowerTick === 0n ? null : fromRaw(range.lowerTick * tickSizeRaw, 9),
|
|
549
|
+
upper: range.higherTick === POS_INF_TICK ? null : fromRaw(range.higherTick * tickSizeRaw, 9)
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
//#endregion
|
|
554
|
+
export { cost_exports };
|
|
555
|
+
//# sourceMappingURL=cost.mjs.map
|