@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
package/dist/predict/client.mjs
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import { TESTNET_PREDICT } from "../deployments/testnet.mjs";
|
|
2
|
+
import { deriveQueueId } from "./queue-id.mjs";
|
|
2
3
|
import { getConfig } from "./config/index.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { PredictInputError, PredictMoveError, PredictPreflightError } from "./errors.mjs";
|
|
5
|
+
import { toGeneratedConfig, toOrdersConfig } from "./config/generated.mjs";
|
|
6
|
+
import { boardPricer } from "./pricing.mjs";
|
|
7
|
+
import { POS_INF_TICK, binaryRangeTicks } from "./ticks.mjs";
|
|
5
8
|
import { fromRaw, priceToRaw, probabilityToRaw, rawToProbability, rawToUsdc, usdcToRaw } from "./units.mjs";
|
|
6
|
-
import {
|
|
9
|
+
import { MIN_PREMIUM, decodeOrderRange } from "./cost.mjs";
|
|
10
|
+
import { ORDER_FLOW_PACKAGE_VERSION, ORDER_KIND, ORDER_STATUS, budgetMintLimits, cashNeedSell, channelTickMs, exactMintLimits, feeCovered, maxMintNow, mintBudget, mintCashNeed, orderKindName, orderView, previewTiming, sellLimits, slippageBand } from "./queue.mjs";
|
|
11
|
+
import { decodeAccountsCreated, decodeBuilderCodeSets, decodeClaims, decodeCohortCommits, decodeDeposits, decodeEnqueues, decodeExpiryPnlRealized, decodeMarketPayoutsCompleted, decodeMints, decodeOpenRecordPayouts, decodePlpCancels, decodePlpRequests, decodePolicyUpdates, decodeQueueEvents, decodeQueueOps, decodeQueuedFills, decodeQueuedRefunds, decodeRecordFunds, decodeRedeems, decodeWithdrawals, exactlyOne } from "./decode.mjs";
|
|
7
12
|
import { simulateWithEvents } from "./reads/inspect.mjs";
|
|
8
13
|
import { accountContract, deriveAccountWrapperIdFrom } from "./tx/common.mjs";
|
|
14
|
+
import { assertOrderFeeAtMost, claimParked, enqueueExactAmount, enqueueExactCost, enqueueExactQuantity, enqueueRedeemOpen, fill, payOpen, rebalanceExpiryCash, refund } from "./tx/queue.mjs";
|
|
15
|
+
import { mintExactAmount, mintExactCost, mintExactQuantity, redeemLive, redeemSettled } from "./tx/trade.mjs";
|
|
16
|
+
import { executionModeFor, lazerPackages, marketQueueState, orderFeeAndBalance, pendingFunds, queuedOrders, quoteMintAnonymous, quoteMintForAccount, quoteRedeemOpen, versionWatermark } from "./reads/queue.mjs";
|
|
9
17
|
import { positionsFromTable, resolvePositionsTable } from "./reads/positions.mjs";
|
|
10
18
|
import { accountBalance, hasPosition } from "./reads/balances.mjs";
|
|
11
|
-
import {
|
|
12
|
-
import { mintExactAmount, mintExactCost, mintExactQuantity, redeemLive, redeemSettled } from "./tx/trade.mjs";
|
|
13
|
-
import { activeMarketIds, currentNav, expiryMarketId, marketState, marketStates, rangePrices, referenceTick } from "./reads/markets.mjs";
|
|
19
|
+
import { activeMarketIds, currentNav, expiryMarketId, marketFeePolicy, marketState, marketStates, rangePrices, referenceTick, settlementPrice } from "./reads/markets.mjs";
|
|
14
20
|
import { poolStats } from "./reads/pool.mjs";
|
|
15
21
|
import { readPricerSnapshot } from "./reads/pricing.mjs";
|
|
16
|
-
import { boardPricer } from "./pricing.mjs";
|
|
17
22
|
import { cancelSupplyRequest, cancelWithdrawRequest, depositFunds, requestSupply, requestWithdraw, setBuilderCode, unsetBuilderCode, withdrawFunds } from "./tx/authed.mjs";
|
|
18
23
|
import { Transaction, coinWithBalance } from "@mysten/sui/transactions";
|
|
19
|
-
import { isValidSuiObjectId } from "@mysten/sui/utils";
|
|
24
|
+
import { isValidSuiObjectId, normalizeSuiAddress } from "@mysten/sui/utils";
|
|
20
25
|
|
|
21
26
|
//#region src/predict/client.ts
|
|
22
27
|
/**
|
|
@@ -24,6 +29,7 @@ import { isValidSuiObjectId } from "@mysten/sui/utils";
|
|
|
24
29
|
* size of the config actually in play; this is the convenience constant for testnet callers.
|
|
25
30
|
*/
|
|
26
31
|
const POSITION_LOT_SIZE = BigInt(TESTNET_PREDICT.units.positionLotSize);
|
|
32
|
+
const NEAR_DOLLAR_PER_CONTRACT = 950000000n;
|
|
27
33
|
function txOf(command) {
|
|
28
34
|
const tx = new Transaction();
|
|
29
35
|
tx.add(command);
|
|
@@ -51,6 +57,12 @@ function predict({ name = "predict", network, config }) {
|
|
|
51
57
|
* returns a finished `Transaction`; callers composing their own PTBs use the generated
|
|
52
58
|
* move-call bindings this subpath exports (`plpMoveCalls`, `expiryMarketMoveCalls`, …).
|
|
53
59
|
*/
|
|
60
|
+
function isOrderFailsLimits(error) {
|
|
61
|
+
return error instanceof PredictMoveError && error.abortName === "EOrderFailsLimits";
|
|
62
|
+
}
|
|
63
|
+
function isPastExpiry(error) {
|
|
64
|
+
return error instanceof PredictMoveError && error.abortName === "ELivePricingExpired";
|
|
65
|
+
}
|
|
54
66
|
var PredictClient = class PredictClient {
|
|
55
67
|
get #config() {
|
|
56
68
|
return toGeneratedConfig(this.cfg);
|
|
@@ -58,6 +70,7 @@ var PredictClient = class PredictClient {
|
|
|
58
70
|
#client;
|
|
59
71
|
#marketCache = /* @__PURE__ */ new Map();
|
|
60
72
|
#positionsCache = /* @__PURE__ */ new Map();
|
|
73
|
+
#knownQueues = /* @__PURE__ */ new Set();
|
|
61
74
|
constructor(opts) {
|
|
62
75
|
this.tx = {
|
|
63
76
|
createManager: () => txOf(accountContract(this.cfg).createAccount()),
|
|
@@ -128,6 +141,118 @@ var PredictClient = class PredictClient {
|
|
|
128
141
|
orderId: opts$1.orderId
|
|
129
142
|
}));
|
|
130
143
|
},
|
|
144
|
+
enqueueMint: async (owner, m, opts$1) => {
|
|
145
|
+
const quantityRaw = usdcToRaw(opts$1.quantity);
|
|
146
|
+
this.#assertLot(quantityRaw);
|
|
147
|
+
const maxCostRaw = usdcToRaw(opts$1.maxCost);
|
|
148
|
+
const maxProbabilityRaw = probabilityToRaw(opts$1.maxProbability);
|
|
149
|
+
return this.#planMint(owner, m, {
|
|
150
|
+
kind: ORDER_KIND.EXACT_QUANTITY,
|
|
151
|
+
maxCostRaw,
|
|
152
|
+
quantityRaw
|
|
153
|
+
}, (orders, target) => enqueueExactQuantity(orders, {
|
|
154
|
+
...target,
|
|
155
|
+
quantityRaw,
|
|
156
|
+
maxCostRaw,
|
|
157
|
+
maxProbabilityRaw
|
|
158
|
+
}));
|
|
159
|
+
},
|
|
160
|
+
enqueueMintAmount: async (owner, m, opts$1) => {
|
|
161
|
+
const maxPremiumRaw = usdcToRaw(opts$1.spend);
|
|
162
|
+
const minQuantityRaw = usdcToRaw(opts$1.minQuantity);
|
|
163
|
+
const maxCostRaw = usdcToRaw(opts$1.maxCost);
|
|
164
|
+
if (maxPremiumRaw < MIN_PREMIUM) throw new PredictPreflightError("min-premium", `spend ${rawToUsdc(maxPremiumRaw)} is below the ${rawToUsdc(MIN_PREMIUM)} minimum premium`);
|
|
165
|
+
return this.#planMint(owner, m, {
|
|
166
|
+
kind: ORDER_KIND.EXACT_AMOUNT,
|
|
167
|
+
maxCostRaw,
|
|
168
|
+
maxPremiumRaw
|
|
169
|
+
}, (orders, target) => enqueueExactAmount(orders, {
|
|
170
|
+
...target,
|
|
171
|
+
maxPremiumRaw,
|
|
172
|
+
minQuantityRaw,
|
|
173
|
+
maxCostRaw
|
|
174
|
+
}));
|
|
175
|
+
},
|
|
176
|
+
enqueueMintCost: async (owner, m, opts$1) => {
|
|
177
|
+
const maxCostRaw = usdcToRaw(opts$1.spend);
|
|
178
|
+
const minQuantityRaw = usdcToRaw(opts$1.minQuantity);
|
|
179
|
+
return this.#planMint(owner, m, {
|
|
180
|
+
kind: ORDER_KIND.EXACT_COST,
|
|
181
|
+
maxCostRaw
|
|
182
|
+
}, (orders, target) => enqueueExactCost(orders, {
|
|
183
|
+
...target,
|
|
184
|
+
maxCostRaw,
|
|
185
|
+
minQuantityRaw
|
|
186
|
+
}));
|
|
187
|
+
},
|
|
188
|
+
enqueueSell: (owner, m, opts$1) => this.#planSell(owner, m, opts$1),
|
|
189
|
+
enqueuePlan: async (owner, m, plan) => {
|
|
190
|
+
if (plan.refusal != null) throw new PredictPreflightError(plan.refusal, `the plan was refused (${plan.refusal})`);
|
|
191
|
+
const target = plan.target;
|
|
192
|
+
const { id, state: marketState$1 } = await this.#resolveMarket(m);
|
|
193
|
+
if (normalizeSuiAddress(owner) !== normalizeSuiAddress(target.owner)) throw new PredictInputError(`the plan was made for owner ${target.owner}, not ${owner}`);
|
|
194
|
+
if (normalizeSuiAddress(id) !== normalizeSuiAddress(target.expiryMarketId)) throw new PredictInputError(`the plan was made for market ${target.expiryMarketId}, not ${id}`);
|
|
195
|
+
const order = plan.order;
|
|
196
|
+
const descriptor = "side" in m ? m : null;
|
|
197
|
+
let placed;
|
|
198
|
+
if (order.builder === "enqueueSell") {
|
|
199
|
+
if (order.options.recordId !== target.recordId) throw new PredictInputError(`the plan was made for record ${target.recordId}, not ${order.options.recordId}`);
|
|
200
|
+
placed = await this.tx.enqueueSell(owner, m, order.options);
|
|
201
|
+
} else {
|
|
202
|
+
if (descriptor == null) throw new PredictInputError("a mint plan needs the market descriptor it was planned with (its strike and side)");
|
|
203
|
+
const { lowerTick, higherTick } = await this.#strikeTicks(descriptor, id, marketState$1);
|
|
204
|
+
if (lowerTick !== target.lowerTick || higherTick !== target.higherTick) throw new PredictInputError("the market descriptor names a different strike or side than the plan, or its reference strike moved: plan again");
|
|
205
|
+
placed = order.builder === "enqueueMintCost" ? await this.tx.enqueueMintCost(owner, descriptor, order.options) : await this.tx.enqueueMint(owner, descriptor, order.options);
|
|
206
|
+
}
|
|
207
|
+
if (placed.preview.raw.orderFee > plan.raw.orderFee) throw new PredictInputError(`the order fee rose from ${rawToUsdc(plan.raw.orderFee)} to ${placed.preview.orderFee} since the plan: plan again`);
|
|
208
|
+
if (order.builder === "enqueueSell") return placed;
|
|
209
|
+
const planned = plan.raw.budget;
|
|
210
|
+
if (placed.preview.raw.budget < planned) throw new PredictPreflightError("fee", `the balance now escrows ${placed.preview.budget}, below the plan's ${rawToUsdc(planned)}`);
|
|
211
|
+
return placed;
|
|
212
|
+
},
|
|
213
|
+
refund: async (m, opts$1 = {}) => {
|
|
214
|
+
const orders = this.#requireDelayedExecution();
|
|
215
|
+
const { id } = await this.#resolveMarket(m);
|
|
216
|
+
return txOf(refund(orders, {
|
|
217
|
+
expiryMarketId: id,
|
|
218
|
+
queueId: await this.#existingQueueId(orders, id),
|
|
219
|
+
maxOrders: BigInt(opts$1.maxOrders ?? 100)
|
|
220
|
+
}));
|
|
221
|
+
},
|
|
222
|
+
claimParked: async (m, recordId) => {
|
|
223
|
+
const orders = this.#requireDelayedExecution();
|
|
224
|
+
const { id } = await this.#resolveMarket(m);
|
|
225
|
+
return txOf(claimParked(orders, {
|
|
226
|
+
expiryMarketId: id,
|
|
227
|
+
queueId: await this.#existingQueueId(orders, id),
|
|
228
|
+
recordId
|
|
229
|
+
}));
|
|
230
|
+
},
|
|
231
|
+
payOpen: async (m, recordId) => {
|
|
232
|
+
const orders = this.#requireDelayedExecution();
|
|
233
|
+
const { id } = await this.#resolveMarket(m);
|
|
234
|
+
return txOf(payOpen(orders, {
|
|
235
|
+
expiryMarketId: id,
|
|
236
|
+
queueId: await this.#existingQueueId(orders, id),
|
|
237
|
+
recordId
|
|
238
|
+
}));
|
|
239
|
+
},
|
|
240
|
+
fill: async (m, opts$1) => {
|
|
241
|
+
const orders = this.#requireDelayedExecution();
|
|
242
|
+
const stateId = opts$1.lazerStateId ?? this.cfg.oracle?.pythLazerState;
|
|
243
|
+
if (!stateId) throw new PredictInputError("fill needs the Pyth Lazer State: pass `lazerStateId`");
|
|
244
|
+
const { id } = await this.#resolveMarket(m);
|
|
245
|
+
const queueId = await this.#existingQueueId(orders, id);
|
|
246
|
+
const lazer = await lazerPackages(this.#client, stateId);
|
|
247
|
+
return txOf(fill(orders, {
|
|
248
|
+
expiryMarketId: id,
|
|
249
|
+
queueId,
|
|
250
|
+
payloads: opts$1.payloads,
|
|
251
|
+
lazer,
|
|
252
|
+
maxOrders: BigInt(opts$1.maxOrders ?? 15),
|
|
253
|
+
refundOverdue: opts$1.refundOverdue
|
|
254
|
+
}));
|
|
255
|
+
},
|
|
131
256
|
supplyPlp: (owner, amountUsdc, options = {}) => txOf(requestSupply({
|
|
132
257
|
config: this.#config,
|
|
133
258
|
arguments: {
|
|
@@ -215,10 +340,480 @@ var PredictClient = class PredictClient {
|
|
|
215
340
|
};
|
|
216
341
|
},
|
|
217
342
|
quoteMint: async (owner, m, opts$1) => {
|
|
343
|
+
if (this.cfg.packages.predictDelayedExecution) {
|
|
344
|
+
const orders = this.#requireDelayedExecution();
|
|
345
|
+
const feeds = this.#feeds(m.underlying);
|
|
346
|
+
const { id, state } = await this.#resolveMarket(m);
|
|
347
|
+
const quantityRaw = usdcToRaw(opts$1.quantity);
|
|
348
|
+
this.#assertLot(quantityRaw);
|
|
349
|
+
const { lowerTick, higherTick } = await this.#strikeTicks(m, id, state);
|
|
350
|
+
const { quote, policy } = await quoteMintForAccount(this.#client, this.#config, {
|
|
351
|
+
expiryMarketId: id,
|
|
352
|
+
wrapperId: this.wrapperIdFor(owner),
|
|
353
|
+
lowerTick,
|
|
354
|
+
higherTick,
|
|
355
|
+
request: {
|
|
356
|
+
shape: "exact-quantity",
|
|
357
|
+
quantityRaw
|
|
358
|
+
},
|
|
359
|
+
ordersConfig: orders,
|
|
360
|
+
...feeds
|
|
361
|
+
});
|
|
362
|
+
return PredictClient.#queuedMintQuote(quote, policy);
|
|
363
|
+
}
|
|
218
364
|
const tx = await this.#buildMint(owner, m, opts$1);
|
|
219
365
|
return this.#quoteMintTransaction(owner, tx);
|
|
220
366
|
},
|
|
221
|
-
quoteMintCost: async (owner, m, opts$1) =>
|
|
367
|
+
quoteMintCost: async (owner, m, opts$1) => {
|
|
368
|
+
if (this.cfg.packages.predictDelayedExecution) {
|
|
369
|
+
const orders = this.#requireDelayedExecution();
|
|
370
|
+
const feeds = this.#feeds(m.underlying);
|
|
371
|
+
const { id, state } = await this.#resolveMarket(m);
|
|
372
|
+
const { lowerTick, higherTick } = await this.#strikeTicks(m, id, state);
|
|
373
|
+
const { policy, availableRaw } = await orderFeeAndBalance(this.#client, orders, owner, this.cfg.quoteCoinType);
|
|
374
|
+
const fee = policy.orderFee;
|
|
375
|
+
const spendRaw = usdcToRaw(opts$1.spend);
|
|
376
|
+
const escrowable = availableRaw > fee ? availableRaw - fee : 0n;
|
|
377
|
+
const { quote } = await quoteMintForAccount(this.#client, this.#config, {
|
|
378
|
+
expiryMarketId: id,
|
|
379
|
+
wrapperId: this.wrapperIdFor(owner),
|
|
380
|
+
lowerTick,
|
|
381
|
+
higherTick,
|
|
382
|
+
request: {
|
|
383
|
+
shape: "exact-cost",
|
|
384
|
+
maxCostRaw: spendRaw < escrowable ? spendRaw : escrowable,
|
|
385
|
+
minQuantityRaw: usdcToRaw(opts$1.minQuantity)
|
|
386
|
+
},
|
|
387
|
+
...feeds
|
|
388
|
+
});
|
|
389
|
+
return PredictClient.#queuedMintQuote(quote, policy);
|
|
390
|
+
}
|
|
391
|
+
return this.#quoteMintTransaction(owner, await this.#buildMintCost(owner, m, opts$1));
|
|
392
|
+
},
|
|
393
|
+
quoteSell: async (owner, m, opts$1) => {
|
|
394
|
+
const orders = this.#requireDelayedExecution();
|
|
395
|
+
const feeds = this.#feeds(m.underlying);
|
|
396
|
+
const { id } = await this.#resolveMarket(m);
|
|
397
|
+
const closeQuantityRaw = usdcToRaw(opts$1.quantity);
|
|
398
|
+
this.#assertLot(closeQuantityRaw);
|
|
399
|
+
const queueId = await this.#existingQueueId(orders, id);
|
|
400
|
+
const { quote, policy } = await quoteRedeemOpen(this.#client, orders, {
|
|
401
|
+
expiryMarketId: id,
|
|
402
|
+
queueId,
|
|
403
|
+
wrapperId: this.wrapperIdFor(owner),
|
|
404
|
+
recordId: opts$1.recordId,
|
|
405
|
+
closeQuantityRaw,
|
|
406
|
+
...feeds
|
|
407
|
+
});
|
|
408
|
+
const orderFee = policy.orderFee;
|
|
409
|
+
return {
|
|
410
|
+
probability: rawToProbability(quote.probability),
|
|
411
|
+
proceeds: rawToUsdc(quote.proceeds),
|
|
412
|
+
net: rawToUsdc(quote.proceeds - orderFee),
|
|
413
|
+
fees: {
|
|
414
|
+
trading: rawToUsdc(quote.tradingFee),
|
|
415
|
+
builder: rawToUsdc(quote.builderFee),
|
|
416
|
+
inventoryImpactRebate: rawToUsdc(quote.inventoryImpactRebate),
|
|
417
|
+
order: rawToUsdc(orderFee)
|
|
418
|
+
},
|
|
419
|
+
quantityClosed: rawToUsdc(quote.closeQuantity),
|
|
420
|
+
raw: {
|
|
421
|
+
probability: quote.probability,
|
|
422
|
+
proceeds: quote.proceeds,
|
|
423
|
+
orderFee,
|
|
424
|
+
quantityClosed: quote.closeQuantity
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
},
|
|
428
|
+
executionMode: async () => executionModeFor(await versionWatermark(this.#client, this.cfg.objects.protocolConfig), this.#recordsDelayedExecution(), this.cfg.packages.predictDelayedExecution != null),
|
|
429
|
+
queue: async (m, owner) => {
|
|
430
|
+
const orders = this.#requireDelayedExecution();
|
|
431
|
+
const { id } = await this.#resolveMarket(m);
|
|
432
|
+
const state = await this.#queueState(orders, id, { owner });
|
|
433
|
+
const nowMs = BigInt(Date.now());
|
|
434
|
+
const policy = state.desk.policy;
|
|
435
|
+
const mode = executionModeFor(state.protocol.versionWatermark, true);
|
|
436
|
+
const timing = previewTiming({
|
|
437
|
+
nowMs,
|
|
438
|
+
policy,
|
|
439
|
+
heads: state.heads,
|
|
440
|
+
expiryMs: state.expiryMs,
|
|
441
|
+
noTradeWindowMs: state.protocol.noTradeWindowMs
|
|
442
|
+
});
|
|
443
|
+
const refusalFor = (side) => {
|
|
444
|
+
try {
|
|
445
|
+
this.#assertQueueOpen(state, side, nowMs);
|
|
446
|
+
return null;
|
|
447
|
+
} catch (e) {
|
|
448
|
+
if (e instanceof PredictPreflightError) return e.code;
|
|
449
|
+
throw e;
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
const refusal = {
|
|
453
|
+
mint: refusalFor("mint"),
|
|
454
|
+
sell: refusalFor("sell")
|
|
455
|
+
};
|
|
456
|
+
return {
|
|
457
|
+
...state,
|
|
458
|
+
mode,
|
|
459
|
+
timing,
|
|
460
|
+
acceptingMints: refusal.mint == null,
|
|
461
|
+
acceptingSells: refusal.sell == null,
|
|
462
|
+
refusal,
|
|
463
|
+
maxMint: {
|
|
464
|
+
exactQuantity: maxMintNow({
|
|
465
|
+
shape: "exact-quantity",
|
|
466
|
+
spareCashRaw: state.spareCash,
|
|
467
|
+
minEntryProbability: state.minEntryProbability,
|
|
468
|
+
lotSize: BigInt(this.cfg.units.positionLotSize),
|
|
469
|
+
asOfMs: nowMs
|
|
470
|
+
}),
|
|
471
|
+
budget: maxMintNow({
|
|
472
|
+
shape: "budget",
|
|
473
|
+
spareCashRaw: state.spareCash,
|
|
474
|
+
minEntryProbability: state.minEntryProbability,
|
|
475
|
+
availableRaw: state.account?.availableRaw,
|
|
476
|
+
orderFeeRaw: policy.orderFee,
|
|
477
|
+
asOfMs: nowMs
|
|
478
|
+
})
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
},
|
|
482
|
+
planMint: async (owner, m, opts$1) => {
|
|
483
|
+
const orders = this.#requireDelayedExecution();
|
|
484
|
+
const feeds = this.#feeds(m.underlying);
|
|
485
|
+
const { id, state: market } = await this.#resolveMarket(m);
|
|
486
|
+
const { lowerTick, higherTick } = await this.#strikeTicks(m, id, market);
|
|
487
|
+
const hasAccount = await this.#hasAccount(owner);
|
|
488
|
+
const state = await this.#queueState(orders, id, hasAccount ? { owner } : {});
|
|
489
|
+
const nowMs = BigInt(Date.now());
|
|
490
|
+
const policy = state.desk.policy;
|
|
491
|
+
const fee = policy.orderFee;
|
|
492
|
+
const availableRaw = state.account?.availableRaw ?? null;
|
|
493
|
+
const lot = BigInt(this.cfg.units.positionLotSize);
|
|
494
|
+
const ticks = {
|
|
495
|
+
expiryMarketId: id,
|
|
496
|
+
lowerTick,
|
|
497
|
+
higherTick,
|
|
498
|
+
...feeds
|
|
499
|
+
};
|
|
500
|
+
const forAccount = (request) => quoteMintForAccount(this.#client, this.#config, {
|
|
501
|
+
...ticks,
|
|
502
|
+
wrapperId: this.wrapperIdFor(owner),
|
|
503
|
+
request
|
|
504
|
+
}).then((r) => r.quote);
|
|
505
|
+
let quote;
|
|
506
|
+
let quoteForAccount;
|
|
507
|
+
let budgetRequested = null;
|
|
508
|
+
if ("amount" in opts$1) {
|
|
509
|
+
const amountRaw = usdcToRaw(opts$1.amount);
|
|
510
|
+
budgetRequested = (opts$1.orderFee ?? "inclusive") === "inclusive" ? amountRaw > fee ? amountRaw - fee : 0n : amountRaw;
|
|
511
|
+
if (budgetRequested === 0n) throw new PredictPreflightError("min-premium", `${opts$1.amount} doesn't cover the ${rawToUsdc(fee)} order fee, so it buys no premium`);
|
|
512
|
+
if (budgetRequested < MIN_PREMIUM) throw new PredictPreflightError("min-premium", `a budget of ${rawToUsdc(budgetRequested)} is below the minimum premium (a mint's premium must be at least ${rawToUsdc(MIN_PREMIUM)} USDC)`);
|
|
513
|
+
quoteForAccount = availableRaw != null && availableRaw > fee && availableRaw - fee >= budgetRequested;
|
|
514
|
+
const budget = budgetRequested;
|
|
515
|
+
const search = () => this.#searchBudgetQuote(ticks, budget, lot).catch(async (error) => {
|
|
516
|
+
if (error instanceof PredictPreflightError && error.code === "min-premium") throw await this.#entryBandRefusal(m) ?? error;
|
|
517
|
+
throw await this.#quoteRefusal(error, { m });
|
|
518
|
+
});
|
|
519
|
+
if (quoteForAccount) try {
|
|
520
|
+
quote = await forAccount({
|
|
521
|
+
shape: "exact-cost",
|
|
522
|
+
maxCostRaw: budget,
|
|
523
|
+
minQuantityRaw: 0n
|
|
524
|
+
});
|
|
525
|
+
} catch (error) {
|
|
526
|
+
if (!isOrderFailsLimits(error)) throw await this.#quoteRefusal(error);
|
|
527
|
+
await search();
|
|
528
|
+
throw error;
|
|
529
|
+
}
|
|
530
|
+
else quote = await search();
|
|
531
|
+
} else {
|
|
532
|
+
const quantityRaw = usdcToRaw(opts$1.quantity);
|
|
533
|
+
this.#assertLot(quantityRaw);
|
|
534
|
+
quoteForAccount = hasAccount;
|
|
535
|
+
try {
|
|
536
|
+
quote = hasAccount ? await forAccount({
|
|
537
|
+
shape: "exact-quantity",
|
|
538
|
+
quantityRaw
|
|
539
|
+
}) : (await quoteMintAnonymous(this.#client, this.#config, {
|
|
540
|
+
...ticks,
|
|
541
|
+
request: {
|
|
542
|
+
shape: "exact-quantity",
|
|
543
|
+
quantityRaw
|
|
544
|
+
}
|
|
545
|
+
})).quote;
|
|
546
|
+
} catch (error) {
|
|
547
|
+
throw await this.#quoteRefusal(error, {
|
|
548
|
+
m,
|
|
549
|
+
quantityRaw
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
const costRaw = quote.allInCost - quote.penaltyFee;
|
|
554
|
+
const slippage = PredictClient.#appliedSlippage(opts$1, quote.entryProbability, state, nowMs);
|
|
555
|
+
const limitsIn = {
|
|
556
|
+
quoteCostRaw: costRaw,
|
|
557
|
+
quoteQuantityRaw: quote.quantity,
|
|
558
|
+
entryProbabilityRaw: quote.entryProbability,
|
|
559
|
+
slippageRaw: slippage.raw,
|
|
560
|
+
feeIncentiveSubsidyRaw: quote.feeIncentiveSubsidy,
|
|
561
|
+
lotSize: lot
|
|
562
|
+
};
|
|
563
|
+
let budgetRaw;
|
|
564
|
+
let minQuantityRaw;
|
|
565
|
+
let admitted = null;
|
|
566
|
+
let maxCostRaw = null;
|
|
567
|
+
let maxProbabilityRaw = null;
|
|
568
|
+
let price;
|
|
569
|
+
let order;
|
|
570
|
+
if (budgetRequested != null) {
|
|
571
|
+
const limits = budgetMintLimits({
|
|
572
|
+
...limitsIn,
|
|
573
|
+
budgetRaw: budgetRequested
|
|
574
|
+
});
|
|
575
|
+
budgetRaw = budgetRequested;
|
|
576
|
+
const unsubsidizedCost = costRaw + quote.feeIncentiveSubsidy;
|
|
577
|
+
const start = unsubsidizedCost === 0n ? quote.quantity : budgetRaw * quote.quantity / unsubsidizedCost / lot * lot;
|
|
578
|
+
admitted = await this.#admittedFloor((quantityRaw) => quoteForAccount ? forAccount({
|
|
579
|
+
shape: "exact-quantity",
|
|
580
|
+
quantityRaw
|
|
581
|
+
}) : quoteMintAnonymous(this.#client, this.#config, {
|
|
582
|
+
...ticks,
|
|
583
|
+
request: {
|
|
584
|
+
shape: "exact-quantity",
|
|
585
|
+
quantityRaw
|
|
586
|
+
}
|
|
587
|
+
}).then((r) => r.quote), budgetRaw, start < quote.quantity ? start : quote.quantity, lot, quote.entryProbability, quote.quantity === 0n ? 0n : unsubsidizedCost * 1000000000n / quote.quantity);
|
|
588
|
+
const ceiling = "quantity" in admitted ? admitted.quantity : 0n;
|
|
589
|
+
minQuantityRaw = limits.minQuantityRaw < ceiling ? limits.minQuantityRaw : ceiling;
|
|
590
|
+
price = limits.pricePerContract;
|
|
591
|
+
order = {
|
|
592
|
+
builder: "enqueueMintCost",
|
|
593
|
+
options: {
|
|
594
|
+
spend: rawToUsdc(budgetRaw),
|
|
595
|
+
minQuantity: rawToUsdc(minQuantityRaw)
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
} else {
|
|
599
|
+
const limits = exactMintLimits(limitsIn);
|
|
600
|
+
maxCostRaw = limits.maxCostRaw;
|
|
601
|
+
maxProbabilityRaw = limits.maxProbabilityRaw;
|
|
602
|
+
budgetRaw = maxCostRaw < quote.quantity ? maxCostRaw : quote.quantity;
|
|
603
|
+
minQuantityRaw = quote.quantity;
|
|
604
|
+
price = limits.pricePerContract;
|
|
605
|
+
order = {
|
|
606
|
+
builder: "enqueueMint",
|
|
607
|
+
options: {
|
|
608
|
+
quantity: rawToUsdc(quote.quantity),
|
|
609
|
+
maxCost: rawToUsdc(maxCostRaw),
|
|
610
|
+
maxProbability: rawToProbability(maxProbabilityRaw)
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
const totalDebitRaw = budgetRaw + fee;
|
|
615
|
+
const expectedDebitRaw = costRaw + fee;
|
|
616
|
+
const inclusive = "amount" in opts$1 && (opts$1.orderFee ?? "inclusive") === "inclusive";
|
|
617
|
+
const refusal = PredictClient.#refusal(() => {
|
|
618
|
+
this.#assertQueueOpen(state, "mint", nowMs);
|
|
619
|
+
if (availableRaw == null || availableRaw < totalDebitRaw) throw new PredictPreflightError("fee", `the balance doesn't cover the plan's ${rawToUsdc(totalDebitRaw)} debit`);
|
|
620
|
+
PredictClient.#assertMintOrder(state, policy, budgetRequested != null ? {
|
|
621
|
+
kind: ORDER_KIND.EXACT_COST,
|
|
622
|
+
maxCostRaw: budgetRaw
|
|
623
|
+
} : {
|
|
624
|
+
kind: ORDER_KIND.EXACT_QUANTITY,
|
|
625
|
+
maxCostRaw: maxCostRaw ?? budgetRaw,
|
|
626
|
+
quantityRaw: quote.quantity
|
|
627
|
+
});
|
|
628
|
+
if (costRaw + quote.feeIncentiveSubsidy > quote.quantity) throw new PredictPreflightError("cost-above-payout", "the all-in cost without the fee subsidy is above the payout");
|
|
629
|
+
if (admitted != null && "refusal" in admitted) throw new PredictPreflightError(admitted.refusal, admitted.refusal === "min-premium" ? `without the fee subsidy, ${rawToUsdc(budgetRaw)} buys no fill that clears the ${rawToUsdc(MIN_PREMIUM)} minimum premium` : admitted.refusal === "entry-band" ? "the entry probability left the market's entry band while the order was sized: plan again, or pick a strike nearer the money" : `without the fee subsidy, ${rawToUsdc(budgetRaw)} buys a fill near $1 a contract, whose admission sizing can't be previewed`);
|
|
630
|
+
});
|
|
631
|
+
let max = maxMintNow(budgetRequested != null ? {
|
|
632
|
+
shape: "budget",
|
|
633
|
+
spareCashRaw: state.spareCash,
|
|
634
|
+
minEntryProbability: state.minEntryProbability,
|
|
635
|
+
availableRaw: availableRaw ?? void 0,
|
|
636
|
+
orderFeeRaw: fee,
|
|
637
|
+
asOfMs: nowMs
|
|
638
|
+
} : {
|
|
639
|
+
shape: "exact-quantity",
|
|
640
|
+
spareCashRaw: state.spareCash,
|
|
641
|
+
minEntryProbability: state.minEntryProbability,
|
|
642
|
+
lotSize: lot,
|
|
643
|
+
asOfMs: nowMs
|
|
644
|
+
}).maxRaw;
|
|
645
|
+
if (budgetRequested == null && availableRaw != null && price.worstRaw > 0n) {
|
|
646
|
+
const spendable = availableRaw > fee ? availableRaw - fee : 0n;
|
|
647
|
+
const perContract = price.worstRaw < 1000000000n ? price.worstRaw : 1000000000n;
|
|
648
|
+
const byBalance = spendable * 1000000000n / perContract / lot * lot;
|
|
649
|
+
if (max == null || byBalance < max) max = byBalance;
|
|
650
|
+
}
|
|
651
|
+
return {
|
|
652
|
+
shape: budgetRequested != null ? "budget" : "exact-quantity",
|
|
653
|
+
target: {
|
|
654
|
+
owner: normalizeSuiAddress(owner),
|
|
655
|
+
expiryMarketId: id,
|
|
656
|
+
lowerTick,
|
|
657
|
+
higherTick
|
|
658
|
+
},
|
|
659
|
+
quote: PredictClient.#queuedMintQuote(quote, policy),
|
|
660
|
+
quoteForAccount,
|
|
661
|
+
slippage: slippage.applied,
|
|
662
|
+
potentialPayout: rawToUsdc(quote.quantity),
|
|
663
|
+
minPayout: rawToUsdc(minQuantityRaw),
|
|
664
|
+
payoutMultiple: Number(quote.quantity) / Number(expectedDebitRaw),
|
|
665
|
+
minPayoutMultiple: Number(minQuantityRaw) / Number(totalDebitRaw),
|
|
666
|
+
pricePerContract: rawToProbability(price.nowRaw),
|
|
667
|
+
worstPricePerContract: rawToProbability(price.worstRaw),
|
|
668
|
+
orderFee: rawToUsdc(fee),
|
|
669
|
+
budget: rawToUsdc(budgetRaw),
|
|
670
|
+
totalDebit: rawToUsdc(totalDebitRaw),
|
|
671
|
+
expectedDebit: rawToUsdc(expectedDebitRaw),
|
|
672
|
+
balance: {
|
|
673
|
+
hasAccount,
|
|
674
|
+
available: availableRaw == null ? null : rawToUsdc(availableRaw),
|
|
675
|
+
covers: availableRaw == null ? null : availableRaw >= totalDebitRaw
|
|
676
|
+
},
|
|
677
|
+
maxNow: max == null ? null : rawToUsdc(inclusive ? max + fee : max),
|
|
678
|
+
timing: previewTiming({
|
|
679
|
+
nowMs,
|
|
680
|
+
policy,
|
|
681
|
+
heads: state.heads,
|
|
682
|
+
expiryMs: state.expiryMs,
|
|
683
|
+
noTradeWindowMs: state.protocol.noTradeWindowMs
|
|
684
|
+
}),
|
|
685
|
+
accepting: refusal == null,
|
|
686
|
+
refusal,
|
|
687
|
+
order,
|
|
688
|
+
raw: {
|
|
689
|
+
budget: budgetRaw,
|
|
690
|
+
orderFee: fee,
|
|
691
|
+
totalDebit: totalDebitRaw,
|
|
692
|
+
slippage: slippage.raw,
|
|
693
|
+
minQuantity: minQuantityRaw,
|
|
694
|
+
maxCost: maxCostRaw,
|
|
695
|
+
maxProbability: maxProbabilityRaw,
|
|
696
|
+
pricePerContract: price.nowRaw,
|
|
697
|
+
worstPricePerContract: price.worstRaw
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
},
|
|
701
|
+
planSell: async (owner, m, opts$1) => {
|
|
702
|
+
const orders = this.#requireDelayedExecution();
|
|
703
|
+
const { id } = await this.#resolveMarket(m);
|
|
704
|
+
const state = await this.#queueState(orders, id, {
|
|
705
|
+
owner,
|
|
706
|
+
recordIds: [opts$1.recordId]
|
|
707
|
+
});
|
|
708
|
+
const record = PredictClient.#assertRecordOpen(state, opts$1.recordId);
|
|
709
|
+
this.#assertSellQuantity(record, usdcToRaw(opts$1.quantity));
|
|
710
|
+
const quote = await this.read.quoteSell(owner, m, {
|
|
711
|
+
recordId: opts$1.recordId,
|
|
712
|
+
quantity: opts$1.quantity
|
|
713
|
+
}).catch(async (error) => {
|
|
714
|
+
throw await this.#quoteRefusal(error);
|
|
715
|
+
});
|
|
716
|
+
const nowMs = BigInt(Date.now());
|
|
717
|
+
const slippage = PredictClient.#appliedSlippage(opts$1, quote.raw.probability, state, nowMs);
|
|
718
|
+
const limits = sellLimits({
|
|
719
|
+
proceedsRaw: quote.raw.proceeds,
|
|
720
|
+
closeQuantityRaw: quote.raw.quantityClosed,
|
|
721
|
+
probabilityRaw: quote.raw.probability,
|
|
722
|
+
slippageRaw: slippage.raw
|
|
723
|
+
});
|
|
724
|
+
const fee = quote.raw.orderFee;
|
|
725
|
+
const refusal = PredictClient.#refusal(() => {
|
|
726
|
+
const { policy } = this.#assertQueueOpen(state, "sell", nowMs);
|
|
727
|
+
this.#assertSellOrder(state, policy, opts$1.recordId, usdcToRaw(opts$1.quantity));
|
|
728
|
+
});
|
|
729
|
+
return {
|
|
730
|
+
target: {
|
|
731
|
+
owner: normalizeSuiAddress(owner),
|
|
732
|
+
expiryMarketId: id,
|
|
733
|
+
recordId: opts$1.recordId
|
|
734
|
+
},
|
|
735
|
+
quote,
|
|
736
|
+
slippage: slippage.applied,
|
|
737
|
+
proceeds: quote.proceeds,
|
|
738
|
+
net: quote.net,
|
|
739
|
+
minProceeds: rawToUsdc(limits.minProceedsRaw),
|
|
740
|
+
minNet: rawToUsdc(limits.minProceedsRaw - fee),
|
|
741
|
+
orderFee: rawToUsdc(fee),
|
|
742
|
+
timing: previewTiming({
|
|
743
|
+
nowMs,
|
|
744
|
+
policy: state.desk.policy,
|
|
745
|
+
heads: state.heads,
|
|
746
|
+
expiryMs: state.expiryMs,
|
|
747
|
+
noTradeWindowMs: state.protocol.noTradeWindowMs
|
|
748
|
+
}),
|
|
749
|
+
accepting: refusal == null,
|
|
750
|
+
refusal,
|
|
751
|
+
order: {
|
|
752
|
+
builder: "enqueueSell",
|
|
753
|
+
options: {
|
|
754
|
+
recordId: opts$1.recordId,
|
|
755
|
+
quantity: opts$1.quantity,
|
|
756
|
+
minProbability: rawToProbability(limits.minProbabilityRaw),
|
|
757
|
+
minProceeds: rawToUsdc(limits.minProceedsRaw)
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
raw: {
|
|
761
|
+
slippage: slippage.raw,
|
|
762
|
+
minProceeds: limits.minProceedsRaw,
|
|
763
|
+
minProbability: limits.minProbabilityRaw,
|
|
764
|
+
orderFee: fee
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
},
|
|
768
|
+
order: async (m, recordId) => (await this.read.orders(m, [recordId]))[0],
|
|
769
|
+
orders: async (m, recordIds) => {
|
|
770
|
+
const orders = this.#requireDelayedExecution();
|
|
771
|
+
const { id } = await this.#resolveMarket(m);
|
|
772
|
+
const queueId = await this.#existingQueueId(orders, id);
|
|
773
|
+
const records = await queuedOrders(this.#client, orders, {
|
|
774
|
+
expiryMarketId: id,
|
|
775
|
+
queueId
|
|
776
|
+
}, recordIds);
|
|
777
|
+
const nowMs = BigInt(Date.now());
|
|
778
|
+
return records.map((record, i) => record ? {
|
|
779
|
+
recordId: recordIds[i],
|
|
780
|
+
record,
|
|
781
|
+
view: orderView(record, nowMs, { lotSize: BigInt(this.cfg.units.positionLotSize) })
|
|
782
|
+
} : null);
|
|
783
|
+
},
|
|
784
|
+
waitForOutcome: async (m, recordId, opts$1 = {}) => {
|
|
785
|
+
const pollMs = opts$1.pollMs ?? 250;
|
|
786
|
+
const deadline = Date.now() + (opts$1.timeoutMs ?? 3e4);
|
|
787
|
+
let seen = false;
|
|
788
|
+
for (;;) {
|
|
789
|
+
const order = await this.read.order(m, recordId);
|
|
790
|
+
const timedOut = Date.now() + pollMs > deadline;
|
|
791
|
+
if (!order) {
|
|
792
|
+
if (seen || timedOut) return {
|
|
793
|
+
outcome: "gone",
|
|
794
|
+
order: null
|
|
795
|
+
};
|
|
796
|
+
} else {
|
|
797
|
+
seen = true;
|
|
798
|
+
const state = order.view.state;
|
|
799
|
+
if (state === "filled" || state === "refunded" || state === "closed") return {
|
|
800
|
+
outcome: state,
|
|
801
|
+
order
|
|
802
|
+
};
|
|
803
|
+
if (timedOut) return {
|
|
804
|
+
outcome: "timeout",
|
|
805
|
+
order
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
await sleep(pollMs, opts$1.signal);
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
pendingFunds: async (owner) => rawToUsdc(await pendingFunds(this.#client, this.wrapperIdFor(owner), this.cfg.quoteCoinType)),
|
|
812
|
+
lazerPackages: (stateId) => {
|
|
813
|
+
const id = stateId ?? this.cfg.oracle?.pythLazerState;
|
|
814
|
+
if (!id) throw new PredictInputError("pass the Pyth Lazer State id");
|
|
815
|
+
return lazerPackages(this.#client, id);
|
|
816
|
+
},
|
|
222
817
|
quoteRedeem: async (owner, m, opts$1) => {
|
|
223
818
|
const tx = await this.#buildRedeem(owner, m, opts$1);
|
|
224
819
|
const events = await simulateWithEvents(this.#client, tx, owner);
|
|
@@ -258,6 +853,19 @@ var PredictClient = class PredictClient {
|
|
|
258
853
|
referencePrice: PredictClient.#referencePriceOf(state)
|
|
259
854
|
};
|
|
260
855
|
},
|
|
856
|
+
settlement: async (m) => {
|
|
857
|
+
const { id, state } = await this.#resolveMarket(m);
|
|
858
|
+
const raw = await settlementPrice(this.#client, this.#config, id);
|
|
859
|
+
return {
|
|
860
|
+
marketId: id,
|
|
861
|
+
expiryMs: state.expiryMs,
|
|
862
|
+
settled: raw != null,
|
|
863
|
+
settlementPrice: raw == null ? null : fromRaw(raw, 9),
|
|
864
|
+
settlementPriceRaw: raw,
|
|
865
|
+
tickSizeRaw: state.tickSizeRaw
|
|
866
|
+
};
|
|
867
|
+
},
|
|
868
|
+
feePolicy: async (m) => marketFeePolicy(this.#client, (await this.#resolveMarket(m)).id),
|
|
261
869
|
balance: async (owner) => rawToUsdc(await accountBalance(this.#client, this.#config, owner, this.cfg.quoteCoinType)),
|
|
262
870
|
plpBalance: (owner) => accountBalance(this.#client, this.#config, owner, this.cfg.coinTypes.plp),
|
|
263
871
|
pool: async () => {
|
|
@@ -282,7 +890,19 @@ var PredictClient = class PredictClient {
|
|
|
282
890
|
withdraw: (r) => exactlyOne(decodeWithdrawals(this.cfg, r), "Withdrawn"),
|
|
283
891
|
plpRequest: (r) => exactlyOne(decodePlpRequests(this.cfg, r), "supply/withdraw-requested"),
|
|
284
892
|
plpCancel: (r) => exactlyOne(decodePlpCancels(this.cfg, r), "RequestCancelled"),
|
|
285
|
-
builderCode: (r) => exactlyOne(decodeBuilderCodeSets(this.cfg, r), "BuilderCodeSet")
|
|
893
|
+
builderCode: (r) => exactlyOne(decodeBuilderCodeSets(this.cfg, r), "BuilderCodeSet"),
|
|
894
|
+
enqueue: (r) => exactlyOne(decodeEnqueues(this.cfg, r), "OrderEnqueued"),
|
|
895
|
+
enqueues: (r) => decodeEnqueues(this.cfg, r),
|
|
896
|
+
queueEvents: (r) => decodeQueueEvents(this.cfg, r),
|
|
897
|
+
cohortCommits: (r) => decodeCohortCommits(this.cfg, r),
|
|
898
|
+
queuedFills: (r) => decodeQueuedFills(this.cfg, r),
|
|
899
|
+
queuedRefunds: (r) => decodeQueuedRefunds(this.cfg, r),
|
|
900
|
+
openRecordPayouts: (r) => decodeOpenRecordPayouts(this.cfg, r),
|
|
901
|
+
marketPayoutsCompleted: (r) => decodeMarketPayoutsCompleted(this.cfg, r),
|
|
902
|
+
queueOps: (r) => decodeQueueOps(this.cfg, r),
|
|
903
|
+
recordFunds: (r) => decodeRecordFunds(this.cfg, r),
|
|
904
|
+
policyUpdates: (r) => decodePolicyUpdates(this.cfg, r),
|
|
905
|
+
expiryPnlRealized: (r) => decodeExpiryPnlRealized(this.cfg, r)
|
|
286
906
|
};
|
|
287
907
|
this.cfg = opts.config ?? getConfig(opts.network);
|
|
288
908
|
this.#client = opts.client;
|
|
@@ -291,6 +911,14 @@ var PredictClient = class PredictClient {
|
|
|
291
911
|
wrapperIdFor(owner) {
|
|
292
912
|
return deriveAccountWrapperIdFrom(this.#config, owner);
|
|
293
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* The deterministic id of a market's `MarketQueue` under the config's queue registry, whether
|
|
916
|
+
* or not it exists yet — no chain read. Throws `PredictInputError` while the config doesn't
|
|
917
|
+
* record delayed execution.
|
|
918
|
+
*/
|
|
919
|
+
queueIdFor(marketId) {
|
|
920
|
+
return deriveQueueId(this.#requireDelayedExecution().queueRegistry, marketId);
|
|
921
|
+
}
|
|
294
922
|
#underlying(underlying) {
|
|
295
923
|
const u = this.cfg.underlyings[underlying];
|
|
296
924
|
if (!u) throw new PredictInputError(`unknown underlying: ${underlying}`);
|
|
@@ -380,6 +1008,134 @@ var PredictClient = class PredictClient {
|
|
|
380
1008
|
const lot = BigInt(this.cfg.units.positionLotSize);
|
|
381
1009
|
if (quantityRaw % lot !== 0n) throw new PredictInputError(`quantity ${quantityRaw} raw is not a whole ${lot}-unit lot (position_lot_size)`);
|
|
382
1010
|
}
|
|
1011
|
+
async #hasAccount(owner) {
|
|
1012
|
+
const { objects: [wrapper] } = await this.#client.core.getObjects({ objectIds: [this.wrapperIdFor(owner)] });
|
|
1013
|
+
return !(wrapper instanceof Error);
|
|
1014
|
+
}
|
|
1015
|
+
static #appliedSlippage(opts, probabilityRaw, state, nowMs) {
|
|
1016
|
+
const cents = opts.slippageCents ?? "auto";
|
|
1017
|
+
if (cents !== "auto") {
|
|
1018
|
+
if (!(Number.isFinite(cents) && cents >= 0 && cents <= 100)) throw new PredictInputError(`slippageCents must be in [0, 100] cents per contract, got ${cents}`);
|
|
1019
|
+
const raw$1 = BigInt(Math.round(cents * 1e7));
|
|
1020
|
+
return {
|
|
1021
|
+
raw: raw$1,
|
|
1022
|
+
applied: {
|
|
1023
|
+
cents: Number(raw$1) / 1e7,
|
|
1024
|
+
source: "input",
|
|
1025
|
+
band: null
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
const policy = state.desk.policy;
|
|
1030
|
+
const band = slippageBand({
|
|
1031
|
+
probability: Math.min(Math.max(rawToProbability(probabilityRaw), 1e-6), .999999),
|
|
1032
|
+
timeToExpiryMs: Number(state.expiryMs > nowMs ? state.expiryMs - nowMs : 0n),
|
|
1033
|
+
delayMs: Number(policy.delayMs),
|
|
1034
|
+
tickMs: Number(channelTickMs(policy.pythChannel)),
|
|
1035
|
+
k: opts.k
|
|
1036
|
+
});
|
|
1037
|
+
const raw = BigInt(Math.ceil(band.deltaProbability * 1e9));
|
|
1038
|
+
return {
|
|
1039
|
+
raw,
|
|
1040
|
+
applied: {
|
|
1041
|
+
cents: Number(raw) / 1e7,
|
|
1042
|
+
source: "auto",
|
|
1043
|
+
band
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
async #quoteRefusal(error, mint) {
|
|
1048
|
+
if (isPastExpiry(error)) return new PredictPreflightError("past-cutoff", "the market reached its expiry, so it has no live price and takes no orders");
|
|
1049
|
+
if (mint != null && isOrderFailsLimits(error)) return await this.#entryBandRefusal(mint.m, mint.quantityRaw) ?? error;
|
|
1050
|
+
return error;
|
|
1051
|
+
}
|
|
1052
|
+
async #entryBandRefusal(m, quantityRaw) {
|
|
1053
|
+
if (m.side === "range") return null;
|
|
1054
|
+
const read = await Promise.all([this.read.price(m), this.read.feePolicy(m)]).catch(() => null);
|
|
1055
|
+
if (read == null) return null;
|
|
1056
|
+
const [prices, policy] = read;
|
|
1057
|
+
const probability = probabilityToRaw(m.side === "up" ? prices.up : prices.down);
|
|
1058
|
+
if (probability < policy.minEntryProbability || probability > policy.maxEntryProbability) return new PredictPreflightError("entry-band", `the ${m.side} probability ${rawToProbability(probability)} is outside the market's entry band [${rawToProbability(policy.minEntryProbability)}, ${rawToProbability(policy.maxEntryProbability)}]: pick a strike nearer the money`);
|
|
1059
|
+
if (quantityRaw != null && quantityRaw * probability / 1000000000n < MIN_PREMIUM) return new PredictPreflightError("min-premium", `${rawToUsdc(quantityRaw)} contracts cost a premium below the ${rawToUsdc(MIN_PREMIUM)} USDC minimum`);
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
async #admittedFloor(quoteAt, budgetRaw, startRaw, lot, entryProbabilityRaw, unsubsidizedPricePerContractRaw) {
|
|
1063
|
+
const ceilLot = (x) => (x + lot - 1n) / lot * lot;
|
|
1064
|
+
const minPremiumQuantity = entryProbabilityRaw === 0n ? 0n : ceilLot((MIN_PREMIUM * 1000000000n + entryProbabilityRaw - 1n) / entryProbabilityRaw);
|
|
1065
|
+
let quantity = startRaw;
|
|
1066
|
+
let raised = false;
|
|
1067
|
+
for (let probe = 0; probe < 5 && quantity > 0n; probe++) {
|
|
1068
|
+
let quote;
|
|
1069
|
+
try {
|
|
1070
|
+
quote = await quoteAt(quantity);
|
|
1071
|
+
} catch (e) {
|
|
1072
|
+
if (!isOrderFailsLimits(e)) throw e;
|
|
1073
|
+
if (!raised && quantity < minPremiumQuantity) {
|
|
1074
|
+
raised = true;
|
|
1075
|
+
quantity = minPremiumQuantity;
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
if (raised || quantity < minPremiumQuantity) return { refusal: "min-premium" };
|
|
1079
|
+
return { refusal: unsubsidizedPricePerContractRaw < NEAR_DOLLAR_PER_CONTRACT ? "entry-band" : "cost-above-payout" };
|
|
1080
|
+
}
|
|
1081
|
+
const unsubsidized = quote.allInCost - quote.penaltyFee + quote.feeIncentiveSubsidy;
|
|
1082
|
+
if (unsubsidized <= budgetRaw) return quantity >= budgetRaw ? { quantity } : { refusal: "cost-above-payout" };
|
|
1083
|
+
if (raised) return { refusal: "min-premium" };
|
|
1084
|
+
const next = quantity * budgetRaw / unsubsidized / lot * lot;
|
|
1085
|
+
quantity = next < quantity ? next : quantity - lot;
|
|
1086
|
+
}
|
|
1087
|
+
return { refusal: "min-premium" };
|
|
1088
|
+
}
|
|
1089
|
+
async #searchBudgetQuote(ticks, budgetRaw, lot) {
|
|
1090
|
+
const floorLot = (x) => x / lot * lot;
|
|
1091
|
+
let refusal = null;
|
|
1092
|
+
let priced = false;
|
|
1093
|
+
const probeQuote = async (request) => {
|
|
1094
|
+
try {
|
|
1095
|
+
const { quote: quote$1 } = await quoteMintAnonymous(this.#client, this.#config, {
|
|
1096
|
+
...ticks,
|
|
1097
|
+
request
|
|
1098
|
+
});
|
|
1099
|
+
priced = true;
|
|
1100
|
+
return quote$1;
|
|
1101
|
+
} catch (e) {
|
|
1102
|
+
if (!isOrderFailsLimits(e)) throw e;
|
|
1103
|
+
refusal ??= e;
|
|
1104
|
+
return null;
|
|
1105
|
+
}
|
|
1106
|
+
};
|
|
1107
|
+
let best = null;
|
|
1108
|
+
let quote = await probeQuote({
|
|
1109
|
+
shape: "exact-amount",
|
|
1110
|
+
maxPremiumRaw: budgetRaw,
|
|
1111
|
+
minQuantityRaw: lot
|
|
1112
|
+
});
|
|
1113
|
+
for (let probe = 1; quote != null; probe++) {
|
|
1114
|
+
const cost = quote.allInCost - quote.penaltyFee;
|
|
1115
|
+
if (cost <= budgetRaw && (best == null || quote.quantity > best.quantity)) best = quote;
|
|
1116
|
+
if (probe === 4) break;
|
|
1117
|
+
const next = cost === 0n ? quote.quantity : floorLot(budgetRaw * quote.quantity / cost);
|
|
1118
|
+
if (next === 0n || next === quote.quantity) break;
|
|
1119
|
+
quote = await probeQuote({
|
|
1120
|
+
shape: "exact-quantity",
|
|
1121
|
+
quantityRaw: next
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
if (best == null) {
|
|
1125
|
+
if (!priced && refusal != null && budgetRaw >= MIN_PREMIUM + lot) throw refusal;
|
|
1126
|
+
throw new PredictPreflightError("min-premium", `a budget of ${rawToUsdc(budgetRaw)} buys no payout at the current price (a mint's premium must be at least ${rawToUsdc(MIN_PREMIUM)} USDC)`);
|
|
1127
|
+
}
|
|
1128
|
+
return best;
|
|
1129
|
+
}
|
|
1130
|
+
static #refusal(check) {
|
|
1131
|
+
try {
|
|
1132
|
+
check();
|
|
1133
|
+
return null;
|
|
1134
|
+
} catch (e) {
|
|
1135
|
+
if (e instanceof PredictPreflightError) return e.code;
|
|
1136
|
+
throw e;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
383
1139
|
async #buildMint(owner, m, opts) {
|
|
384
1140
|
const feeds = this.#feeds(m.underlying);
|
|
385
1141
|
const { id, state } = await this.#resolveMarket(m);
|
|
@@ -451,7 +1207,227 @@ var PredictClient = class PredictClient {
|
|
|
451
1207
|
if (tick == null) throw new PredictInputError(`reference price not set yet for ${m.underlying} @ ${m.expiryMs} — retry shortly or pass a numeric strike`);
|
|
452
1208
|
return tick * state.tickSizeRaw;
|
|
453
1209
|
}
|
|
1210
|
+
#requireDelayedExecution() {
|
|
1211
|
+
return toOrdersConfig(this.cfg);
|
|
1212
|
+
}
|
|
1213
|
+
#recordsDelayedExecution() {
|
|
1214
|
+
const { predictDelayedExecution, predictOrders } = this.cfg.packages;
|
|
1215
|
+
const { orderDesk, queueRegistry } = this.cfg.objects;
|
|
1216
|
+
return Boolean(predictDelayedExecution && predictOrders && orderDesk && queueRegistry);
|
|
1217
|
+
}
|
|
1218
|
+
async #existingQueueId(orders, marketId) {
|
|
1219
|
+
const queueId = deriveQueueId(orders.queueRegistry, marketId);
|
|
1220
|
+
if (this.#knownQueues.has(queueId)) return queueId;
|
|
1221
|
+
const { objects: [queue] } = await this.#client.core.getObjects({ objectIds: [queueId] });
|
|
1222
|
+
if (queue instanceof Error) throw new PredictPreflightError("no-queue", `market ${marketId} has no order queue yet (\`queue::create_and_share\` hasn't run for it)`);
|
|
1223
|
+
this.#knownQueues.add(queueId);
|
|
1224
|
+
return queueId;
|
|
1225
|
+
}
|
|
1226
|
+
async #queueState(orders, marketId, opts = {}) {
|
|
1227
|
+
const queueId = await this.#existingQueueId(orders, marketId);
|
|
1228
|
+
return marketQueueState(this.#client, orders, marketId, {
|
|
1229
|
+
owner: opts.owner,
|
|
1230
|
+
quoteCoinType: this.cfg.quoteCoinType,
|
|
1231
|
+
recordIds: opts.recordIds,
|
|
1232
|
+
queueId
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
#assertQueueOpen(state, side, nowMs) {
|
|
1236
|
+
const policy = state.desk.policy;
|
|
1237
|
+
if (!state.protocol.orderFlowEnabled) throw new PredictPreflightError("not-live", "queued orders aren't live yet: the protocol hasn't enabled the order-flow package");
|
|
1238
|
+
const mode = executionModeFor(state.protocol.versionWatermark, true);
|
|
1239
|
+
if (mode === "retired") throw new PredictPreflightError("retired", "the Predict package version this SDK calls is retired: update the SDK");
|
|
1240
|
+
if (mode !== "delayed") throw new PredictPreflightError("not-live", "queued orders aren't live yet: the protocol's version watermark hasn't been raised");
|
|
1241
|
+
if (state.desk.versionWatermark > ORDER_FLOW_PACKAGE_VERSION) throw new PredictPreflightError("retired", "the order-flow package version this SDK calls is retired: update the SDK");
|
|
1242
|
+
if (state.protocol.frozen) throw new PredictPreflightError("paused", "the protocol is frozen");
|
|
1243
|
+
if (side === "mint" && (state.protocol.tradingPaused || state.mintPaused)) throw new PredictPreflightError("paused", "minting is paused on this market");
|
|
1244
|
+
if (state.stuck) throw new PredictPreflightError("stuck", "pricing is delayed for this market, try again shortly");
|
|
1245
|
+
const [pending, capacity] = side === "mint" ? [state.pending.mints, policy.mintCapacity] : [state.pending.sells, policy.sellCapacity];
|
|
1246
|
+
if (pending >= capacity) throw new PredictPreflightError("queue-full", `the market has ${pending} waiting ${side}s, its maximum`);
|
|
1247
|
+
if (state.account && state.account.waitingOrders >= policy.perAccountCap) throw new PredictPreflightError("account-cap", `the account already has ${state.account.waitingOrders} waiting orders in this market, its maximum`);
|
|
1248
|
+
const timing = previewTiming({
|
|
1249
|
+
nowMs,
|
|
1250
|
+
policy,
|
|
1251
|
+
heads: state.heads,
|
|
1252
|
+
expiryMs: state.expiryMs,
|
|
1253
|
+
noTradeWindowMs: state.protocol.noTradeWindowMs
|
|
1254
|
+
});
|
|
1255
|
+
if (!timing.beforeCutoff) throw new PredictPreflightError("past-cutoff", "this market no longer takes orders before its expiry");
|
|
1256
|
+
return {
|
|
1257
|
+
policy,
|
|
1258
|
+
timing
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
#preview(marketId, kind, timing, policy, budget, cashNeedRaw, spareCashRaw, funding) {
|
|
1262
|
+
const totalDebit = budget + policy.orderFee;
|
|
1263
|
+
return {
|
|
1264
|
+
marketId,
|
|
1265
|
+
kind,
|
|
1266
|
+
kindName: orderKindName(kind),
|
|
1267
|
+
timing,
|
|
1268
|
+
orderFee: rawToUsdc(policy.orderFee),
|
|
1269
|
+
budget: rawToUsdc(budget),
|
|
1270
|
+
totalDebit: rawToUsdc(totalDebit),
|
|
1271
|
+
cashNeedRaw,
|
|
1272
|
+
spareCashRaw,
|
|
1273
|
+
...funding,
|
|
1274
|
+
raw: {
|
|
1275
|
+
orderFee: policy.orderFee,
|
|
1276
|
+
budget,
|
|
1277
|
+
totalDebit
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
async #planMint(owner, m, order, build) {
|
|
1282
|
+
const orders = this.#requireDelayedExecution();
|
|
1283
|
+
const feeds = this.#feeds(m.underlying);
|
|
1284
|
+
const { id, state: market } = await this.#resolveMarket(m);
|
|
1285
|
+
const { lowerTick, higherTick } = await this.#strikeTicks(m, id, market);
|
|
1286
|
+
const thunk = build(orders, {
|
|
1287
|
+
expiryMarketId: id,
|
|
1288
|
+
wrapperId: this.wrapperIdFor(owner),
|
|
1289
|
+
lowerTick,
|
|
1290
|
+
higherTick,
|
|
1291
|
+
...feeds
|
|
1292
|
+
});
|
|
1293
|
+
const state = await this.#queueState(orders, id, { owner });
|
|
1294
|
+
const { policy, timing } = this.#assertQueueOpen(state, "mint", BigInt(Date.now()));
|
|
1295
|
+
const { budget, cashNeed } = PredictClient.#assertMintOrder(state, policy, order);
|
|
1296
|
+
const tx = new Transaction();
|
|
1297
|
+
tx.add(assertOrderFeeAtMost(orders, policy.orderFee));
|
|
1298
|
+
tx.add(thunk);
|
|
1299
|
+
return {
|
|
1300
|
+
transaction: tx,
|
|
1301
|
+
preview: this.#preview(id, order.kind, timing, policy, budget, cashNeed, state.spareCash, {
|
|
1302
|
+
needsFunding: false,
|
|
1303
|
+
fundedInTransaction: false
|
|
1304
|
+
})
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
static #assertMintOrder(state, policy, order) {
|
|
1308
|
+
const available = state.account?.availableRaw ?? 0n;
|
|
1309
|
+
const budget = mintBudget({
|
|
1310
|
+
kind: order.kind,
|
|
1311
|
+
maxCostRaw: order.maxCostRaw,
|
|
1312
|
+
availableRaw: available,
|
|
1313
|
+
orderFeeRaw: policy.orderFee,
|
|
1314
|
+
quantityRaw: order.quantityRaw
|
|
1315
|
+
});
|
|
1316
|
+
if (budget == null) throw new PredictPreflightError("fee", `the balance (${rawToUsdc(available)}) doesn't cover the ${rawToUsdc(policy.orderFee)} order fee`);
|
|
1317
|
+
if (budget < MIN_PREMIUM) throw new PredictPreflightError("min-premium", `the escrowed budget ${rawToUsdc(budget)} is below the ${rawToUsdc(MIN_PREMIUM)} minimum premium`);
|
|
1318
|
+
if (order.kind !== ORDER_KIND.EXACT_QUANTITY && state.minEntryProbability === 0n) throw new PredictPreflightError("market-cash", "this market takes no budget mints");
|
|
1319
|
+
const cashNeed = mintCashNeed({
|
|
1320
|
+
kind: order.kind,
|
|
1321
|
+
budgetRaw: budget,
|
|
1322
|
+
minEntryProbability: state.minEntryProbability,
|
|
1323
|
+
quantityRaw: order.quantityRaw,
|
|
1324
|
+
maxPremiumRaw: order.maxPremiumRaw
|
|
1325
|
+
});
|
|
1326
|
+
if (cashNeed > state.spareCash) throw new PredictPreflightError("market-cash", "this market can't take an order this size right now");
|
|
1327
|
+
return {
|
|
1328
|
+
budget,
|
|
1329
|
+
cashNeed
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
static #assertRecordOpen(state, recordId) {
|
|
1333
|
+
const record = state.records[0];
|
|
1334
|
+
if (!record || record.status !== ORDER_STATUS.OPEN || record.position.order_id === 0n) throw new PredictPreflightError("record-not-open", `record ${recordId} isn't an Open position`);
|
|
1335
|
+
return record;
|
|
1336
|
+
}
|
|
1337
|
+
#assertSellQuantity(record, closeQuantityRaw) {
|
|
1338
|
+
const held = decodeOrderRange(record.position.order_id, BigInt(this.cfg.units.positionLotSize)).quantity;
|
|
1339
|
+
if (closeQuantityRaw > held) throw new PredictInputError(`quantity ${rawToUsdc(closeQuantityRaw)} is above the record's ${rawToUsdc(held)}`);
|
|
1340
|
+
return held;
|
|
1341
|
+
}
|
|
1342
|
+
#assertSellOrder(state, policy, recordId, closeQuantityRaw) {
|
|
1343
|
+
const record = PredictClient.#assertRecordOpen(state, recordId);
|
|
1344
|
+
if (!state.account || normalizeSuiAddress(record.account_id) !== normalizeSuiAddress(state.account.accountId)) throw new PredictPreflightError("not-record-owner", `record ${recordId} belongs to another account`);
|
|
1345
|
+
if (!feeCovered("sell", state.account.availableRaw, policy.orderFee)) throw new PredictPreflightError("fee", `the balance doesn't cover the ${rawToUsdc(policy.orderFee)} order fee`);
|
|
1346
|
+
const held = this.#assertSellQuantity(record, closeQuantityRaw);
|
|
1347
|
+
const min = policy.minSellQuantity;
|
|
1348
|
+
if (closeQuantityRaw < min || closeQuantityRaw < held && held - closeQuantityRaw < min) throw new PredictPreflightError("below-min-sell", `a sell must close at least ${rawToUsdc(min)} and leave either nothing or at least that much`);
|
|
1349
|
+
}
|
|
1350
|
+
async #planSell(owner, m, opts) {
|
|
1351
|
+
const orders = this.#requireDelayedExecution();
|
|
1352
|
+
const feeds = this.#feeds(m.underlying);
|
|
1353
|
+
const { id } = await this.#resolveMarket(m);
|
|
1354
|
+
const closeQuantityRaw = usdcToRaw(opts.quantity);
|
|
1355
|
+
this.#assertLot(closeQuantityRaw);
|
|
1356
|
+
const thunk = enqueueRedeemOpen(orders, {
|
|
1357
|
+
expiryMarketId: id,
|
|
1358
|
+
wrapperId: this.wrapperIdFor(owner),
|
|
1359
|
+
recordId: opts.recordId,
|
|
1360
|
+
closeQuantityRaw,
|
|
1361
|
+
minProbabilityRaw: probabilityToRaw(opts.minProbability),
|
|
1362
|
+
minProceedsRaw: usdcToRaw(opts.minProceeds),
|
|
1363
|
+
...feeds
|
|
1364
|
+
});
|
|
1365
|
+
const state = await this.#queueState(orders, id, {
|
|
1366
|
+
owner,
|
|
1367
|
+
recordIds: [opts.recordId]
|
|
1368
|
+
});
|
|
1369
|
+
const { policy, timing } = this.#assertQueueOpen(state, "sell", BigInt(Date.now()));
|
|
1370
|
+
this.#assertSellOrder(state, policy, opts.recordId, closeQuantityRaw);
|
|
1371
|
+
const cashNeed = cashNeedSell(closeQuantityRaw, state.backingBufferLambda);
|
|
1372
|
+
const needsFunding = cashNeed > state.spareCash;
|
|
1373
|
+
const fund = opts.fundMarket ?? "auto";
|
|
1374
|
+
const funded = fund === "always" || fund === "auto" && needsFunding;
|
|
1375
|
+
const tx = new Transaction();
|
|
1376
|
+
tx.add(assertOrderFeeAtMost(orders, policy.orderFee));
|
|
1377
|
+
tx.add(thunk);
|
|
1378
|
+
if (funded) tx.add(rebalanceExpiryCash(this.#config, { expiryMarketId: id }));
|
|
1379
|
+
return {
|
|
1380
|
+
transaction: tx,
|
|
1381
|
+
preview: this.#preview(id, ORDER_KIND.REDEEM_OPEN, timing, policy, 0n, cashNeed, state.spareCash, {
|
|
1382
|
+
needsFunding,
|
|
1383
|
+
fundedInTransaction: funded
|
|
1384
|
+
})
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
static #queuedMintQuote(q, policy) {
|
|
1388
|
+
const costRaw = q.allInCost - q.penaltyFee;
|
|
1389
|
+
return {
|
|
1390
|
+
entryProbability: rawToProbability(q.entryProbability),
|
|
1391
|
+
premium: rawToUsdc(q.premium),
|
|
1392
|
+
fees: {
|
|
1393
|
+
trading: rawToUsdc(q.tradingFee),
|
|
1394
|
+
subsidy: rawToUsdc(q.feeIncentiveSubsidy),
|
|
1395
|
+
builder: rawToUsdc(q.builderFee),
|
|
1396
|
+
penalty: 0,
|
|
1397
|
+
referral: 0,
|
|
1398
|
+
inventoryImpact: rawToUsdc(q.inventoryImpactCharge)
|
|
1399
|
+
},
|
|
1400
|
+
cost: rawToUsdc(costRaw),
|
|
1401
|
+
quantity: rawToUsdc(q.quantity),
|
|
1402
|
+
raw: {
|
|
1403
|
+
premium: q.premium,
|
|
1404
|
+
cost: costRaw,
|
|
1405
|
+
quantity: q.quantity,
|
|
1406
|
+
entryProbability: q.entryProbability
|
|
1407
|
+
},
|
|
1408
|
+
feesExact: true,
|
|
1409
|
+
queued: true,
|
|
1410
|
+
orderFee: policy ? rawToUsdc(policy.orderFee) : void 0
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
454
1413
|
};
|
|
1414
|
+
function sleep(ms, signal) {
|
|
1415
|
+
return new Promise((resolve, reject) => {
|
|
1416
|
+
if (signal?.aborted) {
|
|
1417
|
+
reject(signal.reason);
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
1420
|
+
const onAbort = () => {
|
|
1421
|
+
clearTimeout(timer);
|
|
1422
|
+
reject(signal?.reason);
|
|
1423
|
+
};
|
|
1424
|
+
const timer = setTimeout(() => {
|
|
1425
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1426
|
+
resolve();
|
|
1427
|
+
}, ms);
|
|
1428
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
455
1431
|
|
|
456
1432
|
//#endregion
|
|
457
1433
|
export { POSITION_LOT_SIZE, PredictClient, predict };
|