@mysten/deepbook-v3 2.6.4 → 2.8.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 +153 -0
- package/PREDICT.md +389 -61
- 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 +13 -13
- 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/order.d.mts +12 -12
- 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_events.d.mts +10 -10
- package/dist/contracts/deepbook_predict/config_events.d.mts +93 -68
- package/dist/contracts/deepbook_predict/config_events.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/config_events.mjs +45 -1
- package/dist/contracts/deepbook_predict/config_events.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/deps/std/type_name.mjs +17 -0
- package/dist/contracts/deepbook_predict/deps/std/type_name.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/expiry_market.d.mts +652 -235
- package/dist/contracts/deepbook_predict/expiry_market.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/expiry_market.mjs +652 -186
- package/dist/contracts/deepbook_predict/expiry_market.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/lp_book.mjs +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/order_events.d.mts +50 -50
- package/dist/contracts/deepbook_predict/order_events.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/order_events.mjs +3 -1
- package/dist/contracts/deepbook_predict/order_events.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/pause_cap.d.mts +5 -5
- package/dist/contracts/deepbook_predict/plp.d.mts +184 -82
- package/dist/contracts/deepbook_predict/plp.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/plp.mjs +126 -7
- package/dist/contracts/deepbook_predict/plp.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/pool_accounting.mjs +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 +91 -58
- package/dist/contracts/deepbook_predict/pricing.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/pricing.mjs +30 -3
- package/dist/contracts/deepbook_predict/pricing.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/pricing_config.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/protocol_config.d.mts +400 -92
- package/dist/contracts/deepbook_predict/protocol_config.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/protocol_config.mjs +451 -61
- package/dist/contracts/deepbook_predict/protocol_config.mjs.map +1 -1
- 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 +1 -1
- package/dist/contracts/deepbook_predict/strike_payout_tree.mjs +17 -12
- package/dist/contracts/deepbook_predict/strike_payout_tree.mjs.map +1 -1
- package/dist/contracts/deepbook_predict/vault_events.d.mts +154 -106
- package/dist/contracts/deepbook_predict/vault_events.d.mts.map +1 -1
- package/dist/contracts/deepbook_predict/vault_events.mjs +57 -1
- package/dist/contracts/deepbook_predict/vault_events.mjs.map +1 -1
- package/dist/contracts/deepbook_predict_math/config-arguments.d.mts +10 -0
- package/dist/contracts/deepbook_predict_math/config-arguments.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_math/lazer_price.d.mts +106 -0
- package/dist/contracts/deepbook_predict_math/lazer_price.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_math/lazer_price.mjs +125 -0
- package/dist/contracts/deepbook_predict_math/lazer_price.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_math/math.d.mts +284 -0
- package/dist/contracts/deepbook_predict_math/math.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_math/math.mjs +364 -0
- package/dist/contracts/deepbook_predict_math/math.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/config-arguments.d.mts +13 -0
- package/dist/contracts/deepbook_predict_orders/config-arguments.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_orders/delayed_execution_config.d.mts +215 -0
- package/dist/contracts/deepbook_predict_orders/delayed_execution_config.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_orders/delayed_execution_config.mjs +215 -0
- package/dist/contracts/deepbook_predict_orders/delayed_execution_config.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/expiry_market.mjs +87 -0
- package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/expiry_market.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/pricing.mjs +52 -0
- package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/pricing.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/deps/fixed_math/i64.mjs +25 -0
- package/dist/contracts/deepbook_predict_orders/deps/fixed_math/i64.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/deps/sui/balance.mjs +21 -0
- package/dist/contracts/deepbook_predict_orders/deps/sui/balance.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/deps/sui/table.mjs +39 -0
- package/dist/contracts/deepbook_predict_orders/deps/sui/table.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/desk.d.mts +187 -0
- package/dist/contracts/deepbook_predict_orders/desk.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_orders/desk.mjs +261 -0
- package/dist/contracts/deepbook_predict_orders/desk.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/order_queue.d.mts +1042 -0
- package/dist/contracts/deepbook_predict_orders/order_queue.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_orders/order_queue.mjs +849 -0
- package/dist/contracts/deepbook_predict_orders/order_queue.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/queue.d.mts +683 -0
- package/dist/contracts/deepbook_predict_orders/queue.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_orders/queue.mjs +912 -0
- package/dist/contracts/deepbook_predict_orders/queue.mjs.map +1 -0
- package/dist/contracts/deepbook_predict_orders/queue_events.d.mts +195 -0
- package/dist/contracts/deepbook_predict_orders/queue_events.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict_orders/queue_events.mjs +187 -0
- package/dist/contracts/deepbook_predict_orders/queue_events.mjs.map +1 -0
- package/dist/contracts/deepbook_sessions/session_config.d.mts +8 -8
- package/dist/contracts/deepbook_sessions/sessions.d.mts +163 -28
- package/dist/contracts/deepbook_sessions/sessions.d.mts.map +1 -1
- package/dist/contracts/deepbook_sessions/sessions.mjs +234 -5
- package/dist/contracts/deepbook_sessions/sessions.mjs.map +1 -1
- package/dist/deployments/mainnet.mjs +7 -4
- package/dist/deployments/mainnet.mjs.map +1 -1
- package/dist/deployments/testnet.mjs +7 -4
- package/dist/deployments/testnet.mjs.map +1 -1
- package/dist/predict/bindings/expiry-market.d.mts +77 -0
- package/dist/predict/bindings/expiry-market.d.mts.map +1 -0
- package/dist/predict/bindings/expiry-market.mjs +139 -0
- package/dist/predict/bindings/expiry-market.mjs.map +1 -0
- package/dist/predict/bindings/protocol-config.d.mts +39 -0
- package/dist/predict/bindings/protocol-config.d.mts.map +1 -0
- package/dist/predict/bindings/protocol-config.mjs +90 -0
- package/dist/predict/bindings/protocol-config.mjs.map +1 -0
- package/dist/predict/bindings/rename.mjs +9 -0
- package/dist/predict/bindings/rename.mjs.map +1 -0
- package/dist/predict/client.d.mts +595 -16
- package/dist/predict/client.d.mts.map +1 -1
- package/dist/predict/client.mjs +986 -10
- package/dist/predict/client.mjs.map +1 -1
- package/dist/predict/config/generated.d.mts +22 -1
- package/dist/predict/config/generated.d.mts.map +1 -1
- package/dist/predict/config/generated.mjs +30 -1
- package/dist/predict/config/generated.mjs.map +1 -1
- package/dist/predict/config/mainnet.mjs +11 -3
- package/dist/predict/config/mainnet.mjs.map +1 -1
- package/dist/predict/config/testnet.mjs +11 -3
- package/dist/predict/config/testnet.mjs.map +1 -1
- package/dist/predict/config/types.d.mts +50 -1
- package/dist/predict/config/types.d.mts.map +1 -1
- package/dist/predict/cost.d.mts +38 -11
- package/dist/predict/cost.d.mts.map +1 -1
- package/dist/predict/cost.mjs +37 -11
- package/dist/predict/cost.mjs.map +1 -1
- package/dist/predict/decode.d.mts +251 -1
- package/dist/predict/decode.d.mts.map +1 -1
- package/dist/predict/decode.mjs +342 -4
- package/dist/predict/decode.mjs.map +1 -1
- package/dist/predict/errors.d.mts +69 -6
- package/dist/predict/errors.d.mts.map +1 -1
- package/dist/predict/errors.mjs +277 -4
- package/dist/predict/errors.mjs.map +1 -1
- package/dist/predict/index.d.mts +21 -10
- package/dist/predict/index.mjs +24 -12
- package/dist/predict/queue-id.d.mts +13 -0
- package/dist/predict/queue-id.d.mts.map +1 -0
- package/dist/predict/queue-id.mjs +19 -0
- package/dist/predict/queue-id.mjs.map +1 -0
- package/dist/predict/queue.d.mts +505 -0
- package/dist/predict/queue.d.mts.map +1 -0
- package/dist/predict/queue.mjs +774 -0
- package/dist/predict/queue.mjs.map +1 -0
- package/dist/predict/reads/balances.mjs +1 -1
- package/dist/predict/reads/markets.mjs +46 -5
- package/dist/predict/reads/markets.mjs.map +1 -1
- package/dist/predict/reads/pool.mjs +1 -1
- package/dist/predict/reads/pricing.d.mts +1 -1
- package/dist/predict/reads/queue.d.mts +105 -0
- package/dist/predict/reads/queue.d.mts.map +1 -0
- package/dist/predict/reads/queue.mjs +445 -0
- package/dist/predict/reads/queue.mjs.map +1 -0
- package/dist/predict/ticks.d.mts +9 -1
- package/dist/predict/ticks.d.mts.map +1 -1
- package/dist/predict/ticks.mjs +18 -1
- package/dist/predict/ticks.mjs.map +1 -1
- package/dist/predict/tx/authed.mjs +1 -1
- package/dist/predict/tx/common.d.mts.map +1 -1
- package/dist/predict/tx/common.mjs +12 -1
- package/dist/predict/tx/common.mjs.map +1 -1
- package/dist/predict/tx/queue.d.mts +220 -0
- package/dist/predict/tx/queue.d.mts.map +1 -0
- package/dist/predict/tx/queue.mjs +399 -0
- package/dist/predict/tx/queue.mjs.map +1 -0
- package/dist/predict/tx/trade.d.mts.map +1 -1
- package/dist/predict/tx/trade.mjs +61 -43
- package/dist/predict/tx/trade.mjs.map +1 -1
- package/dist/sessions.d.mts +90 -2
- package/dist/sessions.d.mts.map +1 -1
- package/dist/sessions.mjs +107 -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/deepbook.d.mts.map +1 -1
- package/dist/transactions/deepbookAdmin.d.mts +4 -4
- package/dist/transactions/deepbookAdmin.d.mts.map +1 -1
- package/dist/transactions/marginAdmin.d.mts +7 -7
- package/dist/transactions/marginAdmin.d.mts.map +1 -1
- package/dist/transactions/marginLiquidations.d.mts +3 -3
- package/dist/transactions/marginMaintainer.d.mts +5 -5
- package/dist/transactions/marginMaintainer.d.mts.map +1 -1
- package/dist/transactions/marginManager.d.mts +32 -32
- package/dist/transactions/marginManager.d.mts.map +1 -1
- package/dist/transactions/marginPool.d.mts +18 -18
- 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 +4 -4
- package/src/contracts/deepbook_predict/config_events.ts +39 -0
- package/src/contracts/deepbook_predict/deps/std/type_name.ts +24 -0
- package/src/contracts/deepbook_predict/expiry_market.ts +960 -169
- package/src/contracts/deepbook_predict/order_events.ts +3 -1
- package/src/contracts/deepbook_predict/plp.ts +150 -9
- package/src/contracts/deepbook_predict/pricing.ts +46 -7
- package/src/contracts/deepbook_predict/pricing_config.ts +3 -1
- package/src/contracts/deepbook_predict/protocol_config.ts +648 -33
- package/src/contracts/deepbook_predict/strike_payout_tree.ts +25 -21
- package/src/contracts/deepbook_predict/vault_events.ts +65 -0
- package/src/contracts/deepbook_predict_math/config-arguments.ts +6 -0
- package/src/contracts/deepbook_predict_math/lazer_price.ts +196 -0
- package/src/contracts/deepbook_predict_math/math.ts +553 -0
- package/src/contracts/deepbook_predict_orders/config-arguments.ts +11 -0
- package/src/contracts/deepbook_predict_orders/delayed_execution_config.ts +430 -0
- package/src/contracts/deepbook_predict_orders/deps/deepbook_predict/expiry_market.ts +108 -0
- package/src/contracts/deepbook_predict_orders/deps/deepbook_predict/pricing.ts +58 -0
- package/src/contracts/deepbook_predict_orders/deps/fixed_math/i64.ts +21 -0
- package/src/contracts/deepbook_predict_orders/deps/sui/balance.ts +19 -0
- package/src/contracts/deepbook_predict_orders/deps/sui/table.ts +37 -0
- package/src/contracts/deepbook_predict_orders/desk.ts +419 -0
- package/src/contracts/deepbook_predict_orders/order_flow.ts +19 -0
- package/src/contracts/deepbook_predict_orders/order_queue.ts +1670 -0
- package/src/contracts/deepbook_predict_orders/queue.ts +1394 -0
- package/src/contracts/deepbook_predict_orders/queue_events.ts +189 -0
- package/src/contracts/deepbook_sessions/sessions.ts +355 -4
- package/src/deployments/mainnet.ts +7 -2
- package/src/deployments/testnet.ts +7 -2
- package/src/deployments/types.ts +14 -1
- package/src/predict/bindings/expiry-market.ts +127 -0
- package/src/predict/bindings/protocol-config.ts +59 -0
- package/src/predict/bindings/rename.ts +14 -0
- package/src/predict/client.ts +2076 -13
- package/src/predict/config/generated.ts +50 -0
- package/src/predict/config/mainnet.ts +16 -2
- package/src/predict/config/testnet.ts +16 -2
- package/src/predict/config/types.ts +51 -1
- package/src/predict/cost.ts +62 -14
- package/src/predict/decode.ts +691 -2
- package/src/predict/errors.ts +391 -14
- package/src/predict/index.ts +87 -6
- package/src/predict/queue-id.ts +22 -0
- package/src/predict/queue.ts +1231 -0
- package/src/predict/reads/markets.ts +30 -0
- package/src/predict/reads/queue.ts +606 -0
- package/src/predict/ticks.ts +35 -0
- package/src/predict/tx/common.ts +25 -1
- package/src/predict/tx/queue.ts +525 -0
- package/src/predict/tx/trade.ts +80 -49
- package/src/sessions.ts +206 -1
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/rolldown_runtime.mjs";
|
|
2
|
+
import { PredictInputError } from "./errors.mjs";
|
|
3
|
+
import { U64_MAX } from "./units.mjs";
|
|
4
|
+
import { FLOAT_SCALING, MAX_QUANTITY_LOTS, POSITION_LOT_SIZE, decodeOrderRange } from "./cost.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/predict/queue.ts
|
|
7
|
+
var queue_exports = /* @__PURE__ */ __exportAll({
|
|
8
|
+
DEADLINE_EXPIRY_MARGIN_MS: () => DEADLINE_EXPIRY_MARGIN_MS,
|
|
9
|
+
DELAYED_EXECUTION_VERSION: () => DELAYED_EXECUTION_VERSION,
|
|
10
|
+
ORDER_FLOW_PACKAGE_VERSION: () => ORDER_FLOW_PACKAGE_VERSION,
|
|
11
|
+
ORDER_KIND: () => ORDER_KIND,
|
|
12
|
+
ORDER_STATUS: () => ORDER_STATUS,
|
|
13
|
+
PREDICT_PACKAGE_VERSION: () => PREDICT_PACKAGE_VERSION,
|
|
14
|
+
PYTH_CHANNEL: () => PYTH_CHANNEL,
|
|
15
|
+
REFUND_REASON: () => REFUND_REASON,
|
|
16
|
+
REFUND_REASONS: () => REFUND_REASONS,
|
|
17
|
+
REFUND_REQUEST_GRACE_MS: () => REFUND_REQUEST_GRACE_MS,
|
|
18
|
+
SETTLE_PHASE: () => SETTLE_PHASE,
|
|
19
|
+
budgetMintLimits: () => budgetMintLimits,
|
|
20
|
+
cashNeedBudget: () => cashNeedBudget,
|
|
21
|
+
cashNeedExactQuantity: () => cashNeedExactQuantity,
|
|
22
|
+
cashNeedSell: () => cashNeedSell,
|
|
23
|
+
channelTickMs: () => channelTickMs,
|
|
24
|
+
exactMintLimits: () => exactMintLimits,
|
|
25
|
+
feeCovered: () => feeCovered,
|
|
26
|
+
isMintKind: () => isMintKind,
|
|
27
|
+
isSellKind: () => isSellKind,
|
|
28
|
+
maxMintNow: () => maxMintNow,
|
|
29
|
+
mintBudget: () => mintBudget,
|
|
30
|
+
mintCashNeed: () => mintCashNeed,
|
|
31
|
+
orderCutoffMs: () => orderCutoffMs,
|
|
32
|
+
orderKindName: () => orderKindName,
|
|
33
|
+
orderStatusName: () => orderStatusName,
|
|
34
|
+
orderView: () => orderView,
|
|
35
|
+
policyFromBcs: () => policyFromBcs,
|
|
36
|
+
previewTiming: () => previewTiming,
|
|
37
|
+
reduceOrderEvents: () => reduceOrderEvents,
|
|
38
|
+
refundReason: () => refundReason,
|
|
39
|
+
sellCashCheck: () => sellCashCheck,
|
|
40
|
+
sellLimits: () => sellLimits,
|
|
41
|
+
slippageBand: () => slippageBand
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* Predict's `constants::current_version` from the upgrade that added delayed execution. Enqueue
|
|
45
|
+
* works once `ProtocolConfig.version_watermark` reaches it (Predict's admission aborts
|
|
46
|
+
* `ECutoverNotReached` until then). The retired immediate trades (`mint_exact_*`, `redeem_live`)
|
|
47
|
+
* always abort in that package, and the older packages they still run in are retired by the same
|
|
48
|
+
* bump. The same on both networks: it is the code's version constant, not the on-chain package
|
|
49
|
+
* version (Mainnet v4, Testnet v5).
|
|
50
|
+
*/
|
|
51
|
+
const DELAYED_EXECUTION_VERSION = 4n;
|
|
52
|
+
/**
|
|
53
|
+
* Predict's `constants::current_version` of the package these bindings were generated from. Every
|
|
54
|
+
* version-gated Predict call checks `chk_version`, which aborts `EPackageVersionDisabled` once
|
|
55
|
+
* `ProtocolConfig.version_watermark` is above it, so a higher watermark retires the Predict code
|
|
56
|
+
* this SDK calls. Bump it with Predict when regenerating.
|
|
57
|
+
*/
|
|
58
|
+
const PREDICT_PACKAGE_VERSION = 4n;
|
|
59
|
+
/**
|
|
60
|
+
* `desk::current_version` of the order-flow package these bindings were generated from. The desk's
|
|
61
|
+
* version floor retires older companion code, so a floor above it means the package this SDK calls
|
|
62
|
+
* aborts `EPackageVersionDisabled`. Bump it with the companion when regenerating.
|
|
63
|
+
*/
|
|
64
|
+
const ORDER_FLOW_PACKAGE_VERSION = 1n;
|
|
65
|
+
/** `queue::phase_*`: what `settle_step` returns, the phase the next call runs. */
|
|
66
|
+
const SETTLE_PHASE = Object.freeze({
|
|
67
|
+
DRAIN: 0,
|
|
68
|
+
PAY: 1,
|
|
69
|
+
DONE: 2
|
|
70
|
+
});
|
|
71
|
+
/** `order_queue::status_*`. Never renumbered on chain; unknown codes still decode. */
|
|
72
|
+
const ORDER_STATUS = Object.freeze({
|
|
73
|
+
PENDING: 0,
|
|
74
|
+
COMMITTED: 1,
|
|
75
|
+
OPEN: 2,
|
|
76
|
+
REFUNDED: 3,
|
|
77
|
+
CLOSED: 4,
|
|
78
|
+
REFUND_DUE: 5
|
|
79
|
+
});
|
|
80
|
+
/** `order_queue::kind_*`. `REDEEM_LIVE` is reserved and never used by v4. */
|
|
81
|
+
const ORDER_KIND = Object.freeze({
|
|
82
|
+
EXACT_QUANTITY: 0,
|
|
83
|
+
EXACT_AMOUNT: 1,
|
|
84
|
+
EXACT_COST: 2,
|
|
85
|
+
REDEEM_LIVE: 3,
|
|
86
|
+
REDEEM_OPEN: 4
|
|
87
|
+
});
|
|
88
|
+
/** `order_queue::reason_*`. `0` in a record's result means filled. */
|
|
89
|
+
const REFUND_REASON = Object.freeze({
|
|
90
|
+
LIMITS: 1,
|
|
91
|
+
ADMISSION: 2,
|
|
92
|
+
NO_PRICE: 3,
|
|
93
|
+
MISSING_NODE: 4,
|
|
94
|
+
DEADLINE: 5,
|
|
95
|
+
FREEZE: 6,
|
|
96
|
+
ADMIN: 7,
|
|
97
|
+
NO_CASH: 8,
|
|
98
|
+
RECIPIENT_DENIED: 9
|
|
99
|
+
});
|
|
100
|
+
/** The Pyth Lazer channels the queue prices on (`delayed_execution_config`). */
|
|
101
|
+
const PYTH_CHANNEL = Object.freeze({
|
|
102
|
+
FIXED_RATE_50MS: 2,
|
|
103
|
+
FIXED_RATE_200MS: 3
|
|
104
|
+
});
|
|
105
|
+
/** Predict's `constants::deadline_expiry_margin_ms`: every deadline is at least this long before expiry. */
|
|
106
|
+
const DEADLINE_EXPIRY_MARGIN_MS = 5000n;
|
|
107
|
+
/**
|
|
108
|
+
* How long after an order's deadline the app waits before offering "Refund my order". Keepers
|
|
109
|
+
* refund overdue orders on their own, so the button only matters when they are all down.
|
|
110
|
+
*/
|
|
111
|
+
const REFUND_REQUEST_GRACE_MS = 5000n;
|
|
112
|
+
const STATUS_NAMES = [
|
|
113
|
+
"pending",
|
|
114
|
+
"committed",
|
|
115
|
+
"open",
|
|
116
|
+
"refunded",
|
|
117
|
+
"closed",
|
|
118
|
+
"refund-due"
|
|
119
|
+
];
|
|
120
|
+
const KIND_NAMES = [
|
|
121
|
+
"exact-quantity",
|
|
122
|
+
"exact-amount",
|
|
123
|
+
"exact-cost",
|
|
124
|
+
"redeem-live",
|
|
125
|
+
"redeem-open"
|
|
126
|
+
];
|
|
127
|
+
/** A status code's name, or `'unknown'` for a code this SDK version predates. */
|
|
128
|
+
function orderStatusName(code) {
|
|
129
|
+
return STATUS_NAMES[code] ?? "unknown";
|
|
130
|
+
}
|
|
131
|
+
/** A kind code's name, or `'unknown'` for a code this SDK version predates. */
|
|
132
|
+
function orderKindName(code) {
|
|
133
|
+
return KIND_NAMES[code] ?? "unknown";
|
|
134
|
+
}
|
|
135
|
+
/** Whether a kind code is a queued mint (exact quantity, exact amount or exact cost). */
|
|
136
|
+
function isMintKind(kind) {
|
|
137
|
+
return kind === ORDER_KIND.EXACT_QUANTITY || kind === ORDER_KIND.EXACT_AMOUNT || kind === ORDER_KIND.EXACT_COST;
|
|
138
|
+
}
|
|
139
|
+
/** Whether a kind code is a queued sell. */
|
|
140
|
+
function isSellKind(kind) {
|
|
141
|
+
return kind === ORDER_KIND.REDEEM_OPEN || kind === ORDER_KIND.REDEEM_LIVE;
|
|
142
|
+
}
|
|
143
|
+
/** Every reason code v4 defines, with its text and fee treatment. */
|
|
144
|
+
const REFUND_REASONS = Object.freeze({
|
|
145
|
+
1: {
|
|
146
|
+
code: 1,
|
|
147
|
+
key: "limits",
|
|
148
|
+
text: "Your price limits weren't met at the fill price. Refunded, the order fee is kept.",
|
|
149
|
+
feeKept: true,
|
|
150
|
+
live: true
|
|
151
|
+
},
|
|
152
|
+
2: {
|
|
153
|
+
code: 2,
|
|
154
|
+
key: "admission",
|
|
155
|
+
text: "The market couldn't accept the order at the fill price. Refunded, the order fee is kept.",
|
|
156
|
+
feeKept: true,
|
|
157
|
+
live: true
|
|
158
|
+
},
|
|
159
|
+
3: {
|
|
160
|
+
code: 3,
|
|
161
|
+
key: "no-price",
|
|
162
|
+
text: "No price arrived for the order. Refunded in full.",
|
|
163
|
+
feeKept: false,
|
|
164
|
+
live: false
|
|
165
|
+
},
|
|
166
|
+
4: {
|
|
167
|
+
code: 4,
|
|
168
|
+
key: "missing-node",
|
|
169
|
+
text: "The market couldn't place the order. Refunded in full.",
|
|
170
|
+
feeKept: false,
|
|
171
|
+
live: true
|
|
172
|
+
},
|
|
173
|
+
5: {
|
|
174
|
+
code: 5,
|
|
175
|
+
key: "deadline",
|
|
176
|
+
text: "The order wasn't priced before its deadline. Refunded in full.",
|
|
177
|
+
feeKept: false,
|
|
178
|
+
live: true
|
|
179
|
+
},
|
|
180
|
+
6: {
|
|
181
|
+
code: 6,
|
|
182
|
+
key: "freeze",
|
|
183
|
+
text: "The protocol was frozen. Refunded in full.",
|
|
184
|
+
feeKept: false,
|
|
185
|
+
live: false
|
|
186
|
+
},
|
|
187
|
+
7: {
|
|
188
|
+
code: 7,
|
|
189
|
+
key: "admin",
|
|
190
|
+
text: "Refunded in full by an admin.",
|
|
191
|
+
feeKept: false,
|
|
192
|
+
live: true
|
|
193
|
+
},
|
|
194
|
+
8: {
|
|
195
|
+
code: 8,
|
|
196
|
+
key: "no-cash",
|
|
197
|
+
text: "The market couldn't pay right now. Refunded in full.",
|
|
198
|
+
feeKept: false,
|
|
199
|
+
live: true
|
|
200
|
+
},
|
|
201
|
+
9: {
|
|
202
|
+
code: 9,
|
|
203
|
+
key: "recipient-denied",
|
|
204
|
+
text: "The account's receive address can't take USDC right now (it is on USDC's deny list, or USDC is paused). Refunded in full, and the refund waits in the order until it can be claimed.",
|
|
205
|
+
feeKept: false,
|
|
206
|
+
live: true
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
/** A reason code's meaning. Unknown codes map to `key: 'unknown'` rather than throwing. */
|
|
210
|
+
function refundReason(code) {
|
|
211
|
+
return REFUND_REASONS[code] ?? {
|
|
212
|
+
code,
|
|
213
|
+
key: "unknown",
|
|
214
|
+
text: `Refunded (code ${code}).`,
|
|
215
|
+
feeKept: null,
|
|
216
|
+
live: false
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/** Map the generated policy layout to {@link DelayedExecutionPolicy}. */
|
|
220
|
+
function policyFromBcs(p) {
|
|
221
|
+
return {
|
|
222
|
+
delayMs: p.delay_ms,
|
|
223
|
+
stallTimeoutMs: p.stall_timeout_ms,
|
|
224
|
+
stuckThresholdMs: p.stuck_threshold_ms,
|
|
225
|
+
gapWaitMs: p.gap_wait_ms,
|
|
226
|
+
pythPriceBufferMs: p.pyth_price_buffer_ms,
|
|
227
|
+
pythChannel: p.pyth_channel,
|
|
228
|
+
sviMaxAgeMs: p.svi_max_age_ms,
|
|
229
|
+
mintCapacity: p.mint_capacity,
|
|
230
|
+
sellCapacity: p.sell_capacity,
|
|
231
|
+
perAccountCap: p.per_account_cap,
|
|
232
|
+
orderFee: p.order_fee,
|
|
233
|
+
minSellQuantity: p.min_sell_quantity,
|
|
234
|
+
settleRefundBatch: p.settle_refund_batch,
|
|
235
|
+
settlePayoutBatch: p.settle_payout_batch
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/** `delayed_execution_config::channel_tick_ms`: 50 ms for channel 2, 200 ms for channel 3. */
|
|
239
|
+
function channelTickMs(channel) {
|
|
240
|
+
if (channel === PYTH_CHANNEL.FIXED_RATE_50MS) return 50n;
|
|
241
|
+
if (channel === PYTH_CHANNEL.FIXED_RATE_200MS) return 200n;
|
|
242
|
+
throw new PredictInputError(`unsupported Pyth Lazer channel ${channel}`);
|
|
243
|
+
}
|
|
244
|
+
function assertUint(value, name, max$1 = U64_MAX) {
|
|
245
|
+
if (typeof value !== "bigint" || value < 0n || value > max$1) throw new PredictInputError(`${name} must be a bigint in [0, ${max$1}], got ${String(value)}`);
|
|
246
|
+
}
|
|
247
|
+
function mulDivUp(x, y, denominator) {
|
|
248
|
+
if (denominator === 0n) throw new PredictInputError("division by zero (EInputZero)");
|
|
249
|
+
return (x * y + denominator - 1n) / denominator;
|
|
250
|
+
}
|
|
251
|
+
function plusOne(need) {
|
|
252
|
+
if (need >= U64_MAX) throw new PredictInputError("cash need overflows u64");
|
|
253
|
+
return need + 1n;
|
|
254
|
+
}
|
|
255
|
+
/** Exact-quantity mint cash need: `⌈quantity · (1 − p_min)⌉ + 1`. */
|
|
256
|
+
function cashNeedExactQuantity(quantity, minEntryProbability) {
|
|
257
|
+
assertUint(quantity, "quantity");
|
|
258
|
+
assertUint(minEntryProbability, "minEntryProbability", FLOAT_SCALING);
|
|
259
|
+
return plusOne(mulDivUp(quantity, FLOAT_SCALING - minEntryProbability, FLOAT_SCALING));
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Budget mint cash need: `⌈(budget + 1) · (1 / p_min − 1)⌉ + 1`, rounded as Move rounds it (one
|
|
263
|
+
* `mul_div_up` of `(budget + 1) · (1e9 − p_min) / p_min`). Exact-amount mints pass
|
|
264
|
+
* `min(max_premium, budget)`. `p_min = 0` throws, as the Move division aborts.
|
|
265
|
+
*/
|
|
266
|
+
function cashNeedBudget(budget, minEntryProbability) {
|
|
267
|
+
assertUint(budget, "budget", U64_MAX - 1n);
|
|
268
|
+
assertUint(minEntryProbability, "minEntryProbability", FLOAT_SCALING);
|
|
269
|
+
return plusOne(mulDivUp(budget + 1n, FLOAT_SCALING - minEntryProbability, minEntryProbability));
|
|
270
|
+
}
|
|
271
|
+
/** Sell cash need: `⌈close_quantity · (1 − λ)⌉ + 1`. */
|
|
272
|
+
function cashNeedSell(closeQuantity, backingBufferLambda) {
|
|
273
|
+
assertUint(closeQuantity, "closeQuantity");
|
|
274
|
+
assertUint(backingBufferLambda, "backingBufferLambda", FLOAT_SCALING);
|
|
275
|
+
return plusOne(mulDivUp(closeQuantity, FLOAT_SCALING - backingBufferLambda, FLOAT_SCALING));
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Whether the account can pay the order fee: a mint needs `available > fee` (it escrows a budget
|
|
279
|
+
* on top), a sell needs `available ≥ fee` (it escrows only the fee). `available` is
|
|
280
|
+
* `account::balance<USDC>`, unsettled accumulator funds included.
|
|
281
|
+
*/
|
|
282
|
+
function feeCovered(side, availableRaw, orderFeeRaw) {
|
|
283
|
+
return side === "mint" ? availableRaw > orderFeeRaw : availableRaw >= orderFeeRaw;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* The budget a queued mint escrows: `min(max_cost, available − fee)`, and for exact quantity also
|
|
287
|
+
* at most the quantity. `null` when the balance doesn't cover the fee. Enqueue debits the budget
|
|
288
|
+
* plus the order fee, and the unspent budget comes back at the fill.
|
|
289
|
+
*/
|
|
290
|
+
function mintBudget(inputs) {
|
|
291
|
+
if (!feeCovered("mint", inputs.availableRaw, inputs.orderFeeRaw)) return null;
|
|
292
|
+
const budget = min(inputs.maxCostRaw, inputs.availableRaw - inputs.orderFeeRaw);
|
|
293
|
+
if (inputs.kind !== ORDER_KIND.EXACT_QUANTITY) return budget;
|
|
294
|
+
if (inputs.quantityRaw == null) throw new PredictInputError("quantityRaw is required for an exact-quantity budget");
|
|
295
|
+
return min(budget, inputs.quantityRaw);
|
|
296
|
+
}
|
|
297
|
+
/** A queued mint's cash need, picking the formula the contract picks for its kind. */
|
|
298
|
+
function mintCashNeed(inputs) {
|
|
299
|
+
const p = inputs.minEntryProbability;
|
|
300
|
+
switch (inputs.kind) {
|
|
301
|
+
case ORDER_KIND.EXACT_QUANTITY:
|
|
302
|
+
if (inputs.quantityRaw == null) throw new PredictInputError("quantityRaw is required");
|
|
303
|
+
return cashNeedExactQuantity(inputs.quantityRaw, p);
|
|
304
|
+
case ORDER_KIND.EXACT_AMOUNT:
|
|
305
|
+
if (inputs.maxPremiumRaw == null) throw new PredictInputError("maxPremiumRaw is required");
|
|
306
|
+
return cashNeedBudget(min(inputs.maxPremiumRaw, inputs.budgetRaw), p);
|
|
307
|
+
case ORDER_KIND.EXACT_COST: return cashNeedBudget(inputs.budgetRaw, p);
|
|
308
|
+
default: throw new PredictInputError(`kind ${inputs.kind} is not a mint`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* A sell's cash need against the market's spare cash. Sells are never refused for market cash at
|
|
313
|
+
* placement: the keeper funds the market before τ, and a sell the market still can't cover at the
|
|
314
|
+
* fill is refunded in full (reason 8). `short` flags that risk, and the sell builder can add
|
|
315
|
+
* `rebalance_expiry_cash` after the enqueue to fund the market at once.
|
|
316
|
+
*/
|
|
317
|
+
function sellCashCheck(closeQuantityRaw, spareCashRaw, backingBufferLambda) {
|
|
318
|
+
const needRaw = cashNeedSell(closeQuantityRaw, backingBufferLambda);
|
|
319
|
+
return {
|
|
320
|
+
needRaw,
|
|
321
|
+
short: needRaw > spareCashRaw
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* The largest queued mint a market's spare cash admits now ("Max right now"). Predict's admission
|
|
326
|
+
* refuses a mint whose cash need is above spare cash (`EInsufficientMarketCash`). For exact quantity this
|
|
327
|
+
* is the largest lot multiple `q` with `cashNeedExactQuantity(q) ≤ S`; for a budget it is the
|
|
328
|
+
* largest `b` with `cashNeedBudget(b) ≤ S`, where `S` is spare cash less the headroom.
|
|
329
|
+
*
|
|
330
|
+
* It is a snapshot: fills lower spare cash, and the keeper's rebalance after each enqueue raises
|
|
331
|
+
* it. Other waiting orders don't count against a mint. For exact quantity this caps only the
|
|
332
|
+
* cash side: size the balance side with `cost.mintCostForBudget` at `available − fee`. A budget
|
|
333
|
+
* mint with `p_min = 0` can't be placed at all (the cash need divides by `p_min`), so it reads 0.
|
|
334
|
+
*/
|
|
335
|
+
function maxMintNow(inputs) {
|
|
336
|
+
const p = inputs.minEntryProbability;
|
|
337
|
+
assertUint(p, "minEntryProbability", FLOAT_SCALING);
|
|
338
|
+
assertUint(inputs.spareCashRaw, "spareCashRaw");
|
|
339
|
+
const headroom = inputs.headroomBps ?? 100n;
|
|
340
|
+
if (headroom < 0n || headroom > 10000n) throw new PredictInputError(`headroomBps must be in [0, 10000], got ${headroom}`);
|
|
341
|
+
const spare = inputs.spareCashRaw - inputs.spareCashRaw * headroom / 10000n;
|
|
342
|
+
const asOfMs = inputs.asOfMs ?? null;
|
|
343
|
+
let cashLimitRaw;
|
|
344
|
+
let balanceLimitRaw = null;
|
|
345
|
+
if (inputs.shape === "exact-quantity") {
|
|
346
|
+
const lot = inputs.lotSize ?? POSITION_LOT_SIZE;
|
|
347
|
+
if (p >= FLOAT_SCALING) cashLimitRaw = null;
|
|
348
|
+
else if (spare < 2n) cashLimitRaw = 0n;
|
|
349
|
+
else {
|
|
350
|
+
const cap = MAX_QUANTITY_LOTS * lot;
|
|
351
|
+
let q = min((spare - 1n) * FLOAT_SCALING / (FLOAT_SCALING - p), cap);
|
|
352
|
+
q -= q % lot;
|
|
353
|
+
while (q > 0n && cashNeedExactQuantity(q, p) > spare) q -= lot;
|
|
354
|
+
cashLimitRaw = q;
|
|
355
|
+
}
|
|
356
|
+
} else {
|
|
357
|
+
if (p === 0n) cashLimitRaw = 0n;
|
|
358
|
+
else if (p >= FLOAT_SCALING) cashLimitRaw = null;
|
|
359
|
+
else if (spare < 2n) cashLimitRaw = 0n;
|
|
360
|
+
else {
|
|
361
|
+
let b = (spare - 1n) * p / (FLOAT_SCALING - p) - 1n;
|
|
362
|
+
while (b > 0n && cashNeedBudget(b, p) > spare) b -= 1n;
|
|
363
|
+
cashLimitRaw = b > 0n ? b : 0n;
|
|
364
|
+
}
|
|
365
|
+
if (inputs.availableRaw != null) {
|
|
366
|
+
const fee = inputs.orderFeeRaw ?? 0n;
|
|
367
|
+
balanceLimitRaw = inputs.availableRaw > fee ? inputs.availableRaw - fee : 0n;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (cashLimitRaw == null && balanceLimitRaw == null) return {
|
|
371
|
+
cashLimitRaw,
|
|
372
|
+
balanceLimitRaw,
|
|
373
|
+
maxRaw: null,
|
|
374
|
+
limitedBy: "none",
|
|
375
|
+
asOfMs
|
|
376
|
+
};
|
|
377
|
+
if (balanceLimitRaw == null || cashLimitRaw != null && cashLimitRaw <= balanceLimitRaw) return {
|
|
378
|
+
cashLimitRaw,
|
|
379
|
+
balanceLimitRaw,
|
|
380
|
+
maxRaw: cashLimitRaw,
|
|
381
|
+
limitedBy: "cash",
|
|
382
|
+
asOfMs
|
|
383
|
+
};
|
|
384
|
+
return {
|
|
385
|
+
cashLimitRaw,
|
|
386
|
+
balanceLimitRaw,
|
|
387
|
+
maxRaw: balanceLimitRaw,
|
|
388
|
+
limitedBy: "balance",
|
|
389
|
+
asOfMs
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* `expiry − max(no_trade_window_ms, stall_timeout_ms + 5_000)`, saturating at 0: enqueue requires
|
|
394
|
+
* the order's τ below it.
|
|
395
|
+
*/
|
|
396
|
+
function orderCutoffMs(expiryMs, policy, noTradeWindowMs) {
|
|
397
|
+
const margin = max(noTradeWindowMs, policy.stallTimeoutMs + DEADLINE_EXPIRY_MARGIN_MS);
|
|
398
|
+
return expiryMs > margin ? expiryMs - margin : 0n;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Preview `order_queue::plan_timing`: τ is the policy channel's last tick at or before
|
|
402
|
+
* `now + delay`, never below the last τ, and pushed past the last committed τ. Display only:
|
|
403
|
+
* the contract uses the consensus timestamp, which can differ from the local clock.
|
|
404
|
+
*/
|
|
405
|
+
function previewTiming(inputs) {
|
|
406
|
+
const { policy, heads } = inputs;
|
|
407
|
+
const tickMs = channelTickMs(policy.pythChannel);
|
|
408
|
+
const rounded = (inputs.nowMs + policy.delayMs) / tickMs * tickMs;
|
|
409
|
+
let tauMs = max(rounded, heads.lastTauMs);
|
|
410
|
+
if (inputs.lastChannel != null && heads.nextId > 0n && inputs.lastChannel !== policy.pythChannel) tauMs = max(rounded, nextTickAfter(heads.lastTauMs, tickMs));
|
|
411
|
+
if (tauMs <= heads.lastCommittedTauMs) tauMs = nextTickAfter(heads.lastCommittedTauMs, tickMs);
|
|
412
|
+
const deadlineMs = min(tauMs + policy.stallTimeoutMs, inputs.expiryMs);
|
|
413
|
+
const cutoffMs = orderCutoffMs(inputs.expiryMs, policy, inputs.noTradeWindowMs);
|
|
414
|
+
return {
|
|
415
|
+
tauMs,
|
|
416
|
+
deadlineMs,
|
|
417
|
+
cutoffMs,
|
|
418
|
+
tickMs,
|
|
419
|
+
beforeCutoff: tauMs < cutoffMs
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function nextTickAfter(timeMs, tickMs) {
|
|
423
|
+
return (timeMs / tickMs + 1n) * tickMs;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* A heuristic band for a queued order's price limits: `Δp ≈ k · φ(Φ⁻¹(p)) · √(h / T)`, the
|
|
427
|
+
* probability move of a digital under Brownian motion over the horizon `h` (delay + tick +
|
|
428
|
+
* resolve + signing), scaled by the time `T` left. Use `maxProbability = p + Δp` on exact-quantity
|
|
429
|
+
* mints and `minProbability = p − Δp` on sells, and size cost caps at the shifted probability.
|
|
430
|
+
* A sizing aid pending product sign-off, not a contract rule.
|
|
431
|
+
*/
|
|
432
|
+
function slippageBand(inputs) {
|
|
433
|
+
const p = inputs.probability;
|
|
434
|
+
if (!(p > 0 && p < 1)) throw new PredictInputError(`probability must be in (0, 1), got ${p}`);
|
|
435
|
+
const horizonMs = inputs.delayMs + inputs.tickMs + (inputs.resolveMs ?? 500) + (inputs.signingMs ?? 500);
|
|
436
|
+
const k = inputs.k ?? 2;
|
|
437
|
+
const delta = inputs.timeToExpiryMs <= horizonMs ? 1 : Math.min(1, k * normalPdf(inverseNormalCdf(p)) * Math.sqrt(horizonMs / inputs.timeToExpiryMs));
|
|
438
|
+
return {
|
|
439
|
+
horizonMs,
|
|
440
|
+
deltaProbability: delta,
|
|
441
|
+
maxProbability: Math.min(1, p + delta),
|
|
442
|
+
minProbability: Math.max(0, p - delta)
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
const COST_ROUNDING_SLACK = 10n;
|
|
446
|
+
function pricePerContract(inputs) {
|
|
447
|
+
const subsidy = inputs.feeIncentiveSubsidyRaw ?? 0n;
|
|
448
|
+
assertUint(inputs.quoteCostRaw, "quoteCostRaw");
|
|
449
|
+
assertUint(inputs.quoteQuantityRaw, "quoteQuantityRaw");
|
|
450
|
+
assertUint(inputs.slippageRaw, "slippageRaw", FLOAT_SCALING);
|
|
451
|
+
assertUint(subsidy, "feeIncentiveSubsidyRaw");
|
|
452
|
+
if (inputs.quoteQuantityRaw === 0n) throw new PredictInputError("the quote buys no payout, so it sizes no limits");
|
|
453
|
+
return {
|
|
454
|
+
nowRaw: mulDivUp(inputs.quoteCostRaw, FLOAT_SCALING, inputs.quoteQuantityRaw),
|
|
455
|
+
worstRaw: mulDivUp(inputs.quoteCostRaw + subsidy, FLOAT_SCALING, inputs.quoteQuantityRaw) + inputs.slippageRaw
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Limits for a queued all-in budget mint (`enqueueMintCost`): the payout floor at the worst price.
|
|
460
|
+
* The fill buys what `budgetRaw` buys at τ and refunds the order when that is below
|
|
461
|
+
* `minQuantityRaw`, so the order fills while the all-in price per $1 of payout stays within
|
|
462
|
+
* `slippageRaw` of the quote.
|
|
463
|
+
*/
|
|
464
|
+
function budgetMintLimits(inputs) {
|
|
465
|
+
assertUint(inputs.budgetRaw, "budgetRaw");
|
|
466
|
+
const price = pricePerContract(inputs);
|
|
467
|
+
const lot = inputs.lotSize ?? POSITION_LOT_SIZE;
|
|
468
|
+
return {
|
|
469
|
+
minQuantityRaw: (inputs.budgetRaw > COST_ROUNDING_SLACK ? inputs.budgetRaw - COST_ROUNDING_SLACK : 0n) * FLOAT_SCALING / price.worstRaw / lot * lot,
|
|
470
|
+
pricePerContract: price
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Limits for a queued exact-quantity mint (`enqueueMint`): the entry-probability cap and the
|
|
475
|
+
* all-in cost cap at the worst price. The cost cap never exceeds the quantity, since a contract
|
|
476
|
+
* never costs more than it pays.
|
|
477
|
+
*/
|
|
478
|
+
function exactMintLimits(inputs) {
|
|
479
|
+
assertUint(inputs.entryProbabilityRaw, "entryProbabilityRaw", FLOAT_SCALING);
|
|
480
|
+
const price = pricePerContract(inputs);
|
|
481
|
+
const maxCostRaw = mulDivUp(inputs.quoteQuantityRaw, price.worstRaw, FLOAT_SCALING);
|
|
482
|
+
const maxProbabilityRaw = inputs.entryProbabilityRaw + inputs.slippageRaw;
|
|
483
|
+
return {
|
|
484
|
+
maxCostRaw: min(maxCostRaw, inputs.quoteQuantityRaw),
|
|
485
|
+
maxProbabilityRaw: min(maxProbabilityRaw, FLOAT_SCALING),
|
|
486
|
+
pricePerContract: price
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Limits for a queued early sell (`enqueueSell`): the close-probability floor and the proceeds
|
|
491
|
+
* floor at the worst price. `proceedsRaw` is the quote's proceeds before the order fee, as
|
|
492
|
+
* `minProceeds` is.
|
|
493
|
+
*/
|
|
494
|
+
function sellLimits(inputs) {
|
|
495
|
+
assertUint(inputs.proceedsRaw, "proceedsRaw");
|
|
496
|
+
assertUint(inputs.closeQuantityRaw, "closeQuantityRaw");
|
|
497
|
+
assertUint(inputs.probabilityRaw, "probabilityRaw", FLOAT_SCALING);
|
|
498
|
+
assertUint(inputs.slippageRaw, "slippageRaw", FLOAT_SCALING);
|
|
499
|
+
const give = mulDivUp(inputs.closeQuantityRaw, inputs.slippageRaw, FLOAT_SCALING);
|
|
500
|
+
return {
|
|
501
|
+
minProceedsRaw: inputs.proceedsRaw > give ? inputs.proceedsRaw - give : 0n,
|
|
502
|
+
minProbabilityRaw: inputs.probabilityRaw > inputs.slippageRaw ? inputs.probabilityRaw - inputs.slippageRaw : 0n
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
function normalPdf(x) {
|
|
506
|
+
return Math.exp(-.5 * x * x) / Math.sqrt(2 * Math.PI);
|
|
507
|
+
}
|
|
508
|
+
function inverseNormalCdf(p) {
|
|
509
|
+
const a = [
|
|
510
|
+
-39.69683028665376,
|
|
511
|
+
220.9460984245205,
|
|
512
|
+
-275.9285104469687,
|
|
513
|
+
138.357751867269,
|
|
514
|
+
-30.66479806614716,
|
|
515
|
+
2.506628277459239
|
|
516
|
+
];
|
|
517
|
+
const b = [
|
|
518
|
+
-54.47609879822406,
|
|
519
|
+
161.5858368580409,
|
|
520
|
+
-155.6989798598866,
|
|
521
|
+
66.80131188771972,
|
|
522
|
+
-13.28068155288572
|
|
523
|
+
];
|
|
524
|
+
const c = [
|
|
525
|
+
-.007784894002430293,
|
|
526
|
+
-.3223964580411365,
|
|
527
|
+
-2.400758277161838,
|
|
528
|
+
-2.549732539343734,
|
|
529
|
+
4.374664141464968,
|
|
530
|
+
2.938163982698783
|
|
531
|
+
];
|
|
532
|
+
const d = [
|
|
533
|
+
.007784695709041462,
|
|
534
|
+
.3224671290700398,
|
|
535
|
+
2.445134137142996,
|
|
536
|
+
3.754408661907416
|
|
537
|
+
];
|
|
538
|
+
const low = .02425;
|
|
539
|
+
if (p < low) {
|
|
540
|
+
const q$1 = Math.sqrt(-2 * Math.log(p));
|
|
541
|
+
return (((((c[0] * q$1 + c[1]) * q$1 + c[2]) * q$1 + c[3]) * q$1 + c[4]) * q$1 + c[5]) / ((((d[0] * q$1 + d[1]) * q$1 + d[2]) * q$1 + d[3]) * q$1 + 1);
|
|
542
|
+
}
|
|
543
|
+
if (p > 1 - low) {
|
|
544
|
+
const q$1 = Math.sqrt(-2 * Math.log(1 - p));
|
|
545
|
+
return -((((((c[0] * q$1 + c[1]) * q$1 + c[2]) * q$1 + c[3]) * q$1 + c[4]) * q$1 + c[5]) / ((((d[0] * q$1 + d[1]) * q$1 + d[2]) * q$1 + d[3]) * q$1 + 1));
|
|
546
|
+
}
|
|
547
|
+
const q = p - .5;
|
|
548
|
+
const r = q * q;
|
|
549
|
+
return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
|
|
550
|
+
}
|
|
551
|
+
function heldPosition(p, lotSize) {
|
|
552
|
+
return p.order_id === 0n ? null : {
|
|
553
|
+
orderId: p.order_id,
|
|
554
|
+
rootId: p.root_id,
|
|
555
|
+
openedAtMs: p.opened_at_ms,
|
|
556
|
+
quantityRaw: decodeOrderRange(p.order_id, lotSize).quantity
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Map a queue record to its display state. `nowMs` drives the refund flags. A record is sellable
|
|
561
|
+
* while it is Open, holds a position, and `nowMs` is before the cutoff (`opts.cutoffMs`, or the
|
|
562
|
+
* record's own placement cutoff when omitted). Unknown status or kind codes map to `unknown`.
|
|
563
|
+
* `opts.lotSize` is the config's position lot (default 10,000, Predict's), which decodes a held
|
|
564
|
+
* position's quantity.
|
|
565
|
+
*/
|
|
566
|
+
function orderView(record, nowMs, opts = {}) {
|
|
567
|
+
const kind = record.kind;
|
|
568
|
+
const base = {
|
|
569
|
+
status: record.status,
|
|
570
|
+
kind,
|
|
571
|
+
kindName: orderKindName(kind),
|
|
572
|
+
side: isMintKind(kind) ? "mint" : isSellKind(kind) ? "sell" : "unknown"
|
|
573
|
+
};
|
|
574
|
+
if (base.side === "unknown") return {
|
|
575
|
+
...base,
|
|
576
|
+
state: "unknown"
|
|
577
|
+
};
|
|
578
|
+
const { tau_ms: tauMs, deadline_ms: deadlineMs } = record.timing;
|
|
579
|
+
const canRequestRefund = nowMs >= deadlineMs + REFUND_REQUEST_GRACE_MS;
|
|
580
|
+
const position = heldPosition(record.position, opts.lotSize);
|
|
581
|
+
const cutoffMs = opts.cutoffMs ?? record.timing.cutoff_ms;
|
|
582
|
+
const sellable = position != null && nowMs < cutoffMs;
|
|
583
|
+
const result = record.result;
|
|
584
|
+
const parkedRaw = record.funds;
|
|
585
|
+
switch (record.status) {
|
|
586
|
+
case ORDER_STATUS.PENDING: return {
|
|
587
|
+
...base,
|
|
588
|
+
state: "placed",
|
|
589
|
+
tauMs,
|
|
590
|
+
deadlineMs,
|
|
591
|
+
awaitingPrice: nowMs >= tauMs,
|
|
592
|
+
autoRefundByMs: deadlineMs,
|
|
593
|
+
canRequestRefund
|
|
594
|
+
};
|
|
595
|
+
case ORDER_STATUS.COMMITTED: return {
|
|
596
|
+
...base,
|
|
597
|
+
state: "priced",
|
|
598
|
+
tauMs,
|
|
599
|
+
tickMs: record.price.tick_ms,
|
|
600
|
+
priceRaw: record.price.spot,
|
|
601
|
+
deadlineMs,
|
|
602
|
+
msToDeadline: deadlineMs > nowMs ? deadlineMs - nowMs : 0n,
|
|
603
|
+
autoRefundByMs: deadlineMs,
|
|
604
|
+
canRequestRefund
|
|
605
|
+
};
|
|
606
|
+
case ORDER_STATUS.REFUND_DUE: return {
|
|
607
|
+
...base,
|
|
608
|
+
state: "refunding",
|
|
609
|
+
reason: refundReason(result.reason),
|
|
610
|
+
deadlineMs,
|
|
611
|
+
canRequestRefund
|
|
612
|
+
};
|
|
613
|
+
case ORDER_STATUS.OPEN:
|
|
614
|
+
if (base.side === "sell" && result.reason > 0) return {
|
|
615
|
+
...base,
|
|
616
|
+
state: "refunded",
|
|
617
|
+
reason: refundReason(result.reason),
|
|
618
|
+
finishedAtMs: result.finished_at_ms,
|
|
619
|
+
positionBackAsOpenRecord: true,
|
|
620
|
+
position,
|
|
621
|
+
sellable,
|
|
622
|
+
parkedRaw
|
|
623
|
+
};
|
|
624
|
+
return {
|
|
625
|
+
...base,
|
|
626
|
+
state: "filled",
|
|
627
|
+
quantityRaw: result.quantity,
|
|
628
|
+
amountRaw: result.amount,
|
|
629
|
+
finishedAtMs: result.finished_at_ms,
|
|
630
|
+
position,
|
|
631
|
+
sellable,
|
|
632
|
+
parkedRaw
|
|
633
|
+
};
|
|
634
|
+
case ORDER_STATUS.REFUNDED: return {
|
|
635
|
+
...base,
|
|
636
|
+
state: "refunded",
|
|
637
|
+
reason: refundReason(result.reason),
|
|
638
|
+
finishedAtMs: result.finished_at_ms,
|
|
639
|
+
positionBackAsOpenRecord: false,
|
|
640
|
+
position: null,
|
|
641
|
+
sellable: false,
|
|
642
|
+
parkedRaw
|
|
643
|
+
};
|
|
644
|
+
case ORDER_STATUS.CLOSED:
|
|
645
|
+
if (base.side === "sell" && result.reason === 0 && result.quantity > 0n) return {
|
|
646
|
+
...base,
|
|
647
|
+
state: "filled",
|
|
648
|
+
quantityRaw: result.quantity,
|
|
649
|
+
amountRaw: result.amount,
|
|
650
|
+
finishedAtMs: result.finished_at_ms,
|
|
651
|
+
position: null,
|
|
652
|
+
sellable: false,
|
|
653
|
+
parkedRaw
|
|
654
|
+
};
|
|
655
|
+
return {
|
|
656
|
+
...base,
|
|
657
|
+
state: "closed",
|
|
658
|
+
quantityRaw: result.quantity,
|
|
659
|
+
amountRaw: result.amount,
|
|
660
|
+
finishedAtMs: result.finished_at_ms,
|
|
661
|
+
parkedRaw
|
|
662
|
+
};
|
|
663
|
+
default: return {
|
|
664
|
+
...base,
|
|
665
|
+
state: "unknown"
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Fold decoded queue events (in chain order) into per-record states, keyed `marketId:recordId`.
|
|
671
|
+
* The app shows Placed from the enqueue's own effects, Priced at the cohort commit, and switches to
|
|
672
|
+
* Filled or Refunded on `QueuedOrderFilled` / `QueuedOrderRefunded`. Events for records that never
|
|
673
|
+
* appeared enqueued still create an entry, so a partial event window works.
|
|
674
|
+
*/
|
|
675
|
+
function reduceOrderEvents(events, into = /* @__PURE__ */ new Map()) {
|
|
676
|
+
const entry = (marketId, recordId) => {
|
|
677
|
+
const key = `${marketId}:${recordId}`;
|
|
678
|
+
let s = into.get(key);
|
|
679
|
+
if (!s) {
|
|
680
|
+
s = {
|
|
681
|
+
marketId,
|
|
682
|
+
recordId,
|
|
683
|
+
state: "placed",
|
|
684
|
+
kind: null,
|
|
685
|
+
tauMs: null,
|
|
686
|
+
deadlineMs: null,
|
|
687
|
+
price: null,
|
|
688
|
+
tickMs: null,
|
|
689
|
+
reason: null,
|
|
690
|
+
position: null,
|
|
691
|
+
sourceRecordId: null,
|
|
692
|
+
payoutRaw: null,
|
|
693
|
+
payoutSkipped: false,
|
|
694
|
+
parkedRaw: 0n
|
|
695
|
+
};
|
|
696
|
+
into.set(key, s);
|
|
697
|
+
}
|
|
698
|
+
return s;
|
|
699
|
+
};
|
|
700
|
+
for (const e of events) switch (e.type) {
|
|
701
|
+
case "enqueued": {
|
|
702
|
+
const s = entry(e.marketId, e.recordId);
|
|
703
|
+
s.kind = e.kind;
|
|
704
|
+
s.tauMs = e.timing.tauMs;
|
|
705
|
+
s.deadlineMs = e.timing.deadlineMs;
|
|
706
|
+
s.position = e.position;
|
|
707
|
+
s.sourceRecordId = e.sourceRecordId;
|
|
708
|
+
if (e.sourceRecordId != null) {
|
|
709
|
+
const source = entry(e.marketId, e.sourceRecordId);
|
|
710
|
+
source.state = "closed";
|
|
711
|
+
source.position = null;
|
|
712
|
+
}
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
case "cohort-committed":
|
|
716
|
+
for (const s of into.values()) if (s.marketId === e.marketId && s.state === "placed" && s.recordId >= e.firstRecordId && s.recordId <= e.lastRecordId) {
|
|
717
|
+
s.state = "priced";
|
|
718
|
+
s.price = e.price;
|
|
719
|
+
s.tickMs = e.tickMs;
|
|
720
|
+
}
|
|
721
|
+
break;
|
|
722
|
+
case "filled": {
|
|
723
|
+
const s = entry(e.marketId, e.recordId);
|
|
724
|
+
s.state = "filled";
|
|
725
|
+
s.kind = e.kind;
|
|
726
|
+
s.tickMs = e.tickMs;
|
|
727
|
+
s.position = e.position;
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
case "refunded": {
|
|
731
|
+
const s = entry(e.marketId, e.recordId);
|
|
732
|
+
s.state = "refunded";
|
|
733
|
+
s.kind = e.kind;
|
|
734
|
+
s.reason = e.reason;
|
|
735
|
+
if (!e.positionReturned) s.position = null;
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
case "open-record-settled": {
|
|
739
|
+
const s = entry(e.marketId, e.recordId);
|
|
740
|
+
s.state = "settled";
|
|
741
|
+
s.payoutRaw = e.raw.payout;
|
|
742
|
+
s.payoutSkipped = false;
|
|
743
|
+
s.position = null;
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
case "open-record-payout-skipped": {
|
|
747
|
+
const s = entry(e.marketId, e.recordId);
|
|
748
|
+
s.payoutSkipped = true;
|
|
749
|
+
break;
|
|
750
|
+
}
|
|
751
|
+
case "record-funds-parked": {
|
|
752
|
+
const s = entry(e.marketId, e.recordId);
|
|
753
|
+
s.parkedRaw += e.raw.amount;
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
case "record-funds-claimed": {
|
|
757
|
+
const s = entry(e.marketId, e.recordId);
|
|
758
|
+
s.parkedRaw = 0n;
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
default: break;
|
|
762
|
+
}
|
|
763
|
+
return into;
|
|
764
|
+
}
|
|
765
|
+
function min(a, b) {
|
|
766
|
+
return a < b ? a : b;
|
|
767
|
+
}
|
|
768
|
+
function max(a, b) {
|
|
769
|
+
return a > b ? a : b;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
//#endregion
|
|
773
|
+
export { DELAYED_EXECUTION_VERSION, ORDER_FLOW_PACKAGE_VERSION, ORDER_KIND, ORDER_STATUS, PREDICT_PACKAGE_VERSION, budgetMintLimits, cashNeedSell, channelTickMs, exactMintLimits, feeCovered, isMintKind, isSellKind, maxMintNow, mintBudget, mintCashNeed, orderKindName, orderView, policyFromBcs, previewTiming, queue_exports, refundReason, sellLimits, slippageBand };
|
|
774
|
+
//# sourceMappingURL=queue.mjs.map
|