@mysten/deepbook-v3 2.0.1 → 2.1.4
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 +85 -0
- package/PREDICT.md +256 -0
- package/README.md +116 -0
- package/dist/account.d.mts +139 -0
- package/dist/account.d.mts.map +1 -0
- package/dist/account.mjs +181 -0
- package/dist/account.mjs.map +1 -0
- package/dist/bcs/integers.mjs +23 -0
- package/dist/bcs/integers.mjs.map +1 -0
- package/dist/client.d.mts +2 -2
- package/dist/contracts/account/account.d.mts +382 -0
- package/dist/contracts/account/account.d.mts.map +1 -0
- package/dist/contracts/account/account.mjs +443 -0
- package/dist/contracts/account/account.mjs.map +1 -0
- package/dist/contracts/account/account_events.d.mts +41 -0
- package/dist/contracts/account/account_events.d.mts.map +1 -0
- package/dist/contracts/account/account_events.mjs +72 -0
- package/dist/contracts/account/account_events.mjs.map +1 -0
- package/dist/contracts/account/account_registry.d.mts +210 -0
- package/dist/contracts/account/account_registry.d.mts.map +1 -0
- package/dist/contracts/account/account_registry.mjs +263 -0
- package/dist/contracts/account/account_registry.mjs.map +1 -0
- package/dist/contracts/account/config-arguments.d.mts +10 -0
- package/dist/contracts/account/config-arguments.d.mts.map +1 -0
- package/dist/contracts/account/deps/sui/bag.mjs +44 -0
- package/dist/contracts/account/deps/sui/bag.mjs.map +1 -0
- 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/deep_price.d.mts.map +1 -1
- package/dist/contracts/deepbook/order.d.mts +12 -12
- package/dist/contracts/deepbook_predict/builder_code_events.mjs +38 -0
- package/dist/contracts/deepbook_predict/builder_code_events.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/config-arguments.d.mts +13 -0
- package/dist/contracts/deepbook_predict/config-arguments.d.mts.map +1 -0
- package/dist/contracts/deepbook_predict/deps/fixed_math/i64.mjs +25 -0
- package/dist/contracts/deepbook_predict/deps/fixed_math/i64.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/deps/sui/balance.mjs +25 -0
- package/dist/contracts/deepbook_predict/deps/sui/balance.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/deps/sui/coin.mjs +24 -0
- package/dist/contracts/deepbook_predict/deps/sui/coin.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/deps/sui/table.mjs +39 -0
- package/dist/contracts/deepbook_predict/deps/sui/table.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/deps/sui/vec_set.mjs +26 -0
- package/dist/contracts/deepbook_predict/deps/sui/vec_set.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/ewma.mjs +29 -0
- package/dist/contracts/deepbook_predict/ewma.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/expiry_cash.mjs +27 -0
- package/dist/contracts/deepbook_predict/expiry_cash.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/expiry_market.mjs +367 -0
- package/dist/contracts/deepbook_predict/expiry_market.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/lp_book.mjs +92 -0
- package/dist/contracts/deepbook_predict/lp_book.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/market_manager.mjs +59 -0
- package/dist/contracts/deepbook_predict/market_manager.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/order.mjs +26 -0
- package/dist/contracts/deepbook_predict/order.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/order_events.mjs +84 -0
- package/dist/contracts/deepbook_predict/order_events.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/plp.mjs +284 -0
- package/dist/contracts/deepbook_predict/plp.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/pool_accounting.mjs +58 -0
- package/dist/contracts/deepbook_predict/pool_accounting.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/predict_account.mjs +106 -0
- package/dist/contracts/deepbook_predict/predict_account.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/pricing.mjs +80 -0
- package/dist/contracts/deepbook_predict/pricing.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/range_codec.mjs +41 -0
- package/dist/contracts/deepbook_predict/range_codec.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/registry.mjs +55 -0
- package/dist/contracts/deepbook_predict/registry.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/strike_exposure.mjs +65 -0
- package/dist/contracts/deepbook_predict/strike_exposure.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/strike_exposure_config.mjs +33 -0
- package/dist/contracts/deepbook_predict/strike_exposure_config.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/strike_payout_tree.mjs +72 -0
- package/dist/contracts/deepbook_predict/strike_payout_tree.mjs.map +1 -0
- package/dist/contracts/deepbook_predict/vault_events.mjs +184 -0
- package/dist/contracts/deepbook_predict/vault_events.mjs.map +1 -0
- package/dist/contracts/deepbook_sessions/config-arguments.d.mts +10 -0
- package/dist/contracts/deepbook_sessions/config-arguments.d.mts.map +1 -0
- package/dist/contracts/deepbook_sessions/deps/sui/vec_map.mjs +37 -0
- package/dist/contracts/deepbook_sessions/deps/sui/vec_map.mjs.map +1 -0
- package/dist/contracts/deepbook_sessions/session_config.d.mts +63 -0
- package/dist/contracts/deepbook_sessions/session_config.d.mts.map +1 -0
- package/dist/contracts/deepbook_sessions/session_config.mjs +82 -0
- package/dist/contracts/deepbook_sessions/session_config.mjs.map +1 -0
- package/dist/contracts/deepbook_sessions/sessions.d.mts +275 -0
- package/dist/contracts/deepbook_sessions/sessions.d.mts.map +1 -0
- package/dist/contracts/deepbook_sessions/sessions.mjs +443 -0
- package/dist/contracts/deepbook_sessions/sessions.mjs.map +1 -0
- package/dist/contracts/utils/index.d.mts +18 -1
- package/dist/contracts/utils/index.d.mts.map +1 -1
- package/dist/deployments/index.d.mts +31 -0
- package/dist/deployments/index.d.mts.map +1 -0
- package/dist/deployments/index.mjs +30 -0
- package/dist/deployments/index.mjs.map +1 -0
- package/dist/deployments/testnet.d.mts +14 -0
- package/dist/deployments/testnet.d.mts.map +1 -0
- package/dist/deployments/testnet.mjs +73 -0
- package/dist/deployments/testnet.mjs.map +1 -0
- package/dist/deployments/types.d.mts +36 -0
- package/dist/deployments/types.d.mts.map +1 -0
- package/dist/index.mjs +0 -1
- package/dist/predict/client.d.mts +255 -0
- package/dist/predict/client.d.mts.map +1 -0
- package/dist/predict/client.mjs +436 -0
- package/dist/predict/client.mjs.map +1 -0
- package/dist/predict/config/generated.d.mts +29 -0
- package/dist/predict/config/generated.d.mts.map +1 -0
- package/dist/predict/config/generated.mjs +16 -0
- package/dist/predict/config/generated.mjs.map +1 -0
- package/dist/predict/config/index.d.mts +10 -0
- package/dist/predict/config/index.d.mts.map +1 -0
- package/dist/predict/config/index.mjs +13 -0
- package/dist/predict/config/index.mjs.map +1 -0
- package/dist/predict/config/testnet.d.mts +17 -0
- package/dist/predict/config/testnet.d.mts.map +1 -0
- package/dist/predict/config/testnet.mjs +26 -0
- package/dist/predict/config/testnet.mjs.map +1 -0
- package/dist/predict/config/types.d.mts +55 -0
- package/dist/predict/config/types.d.mts.map +1 -0
- package/dist/predict/decode.d.mts +162 -0
- package/dist/predict/decode.d.mts.map +1 -0
- package/dist/predict/decode.mjs +175 -0
- package/dist/predict/decode.mjs.map +1 -0
- package/dist/predict/errors.d.mts +42 -0
- package/dist/predict/errors.d.mts.map +1 -0
- package/dist/predict/errors.mjs +37 -0
- package/dist/predict/errors.mjs.map +1 -0
- package/dist/predict/index.d.mts +18 -0
- package/dist/predict/index.mjs +14 -0
- package/dist/predict/pricing.d.mts +73 -0
- package/dist/predict/pricing.d.mts.map +1 -0
- package/dist/predict/pricing.mjs +129 -0
- package/dist/predict/pricing.mjs.map +1 -0
- package/dist/predict/reads/balances.mjs +41 -0
- package/dist/predict/reads/balances.mjs.map +1 -0
- package/dist/predict/reads/inspect.d.mts +8 -0
- package/dist/predict/reads/inspect.d.mts.map +1 -0
- package/dist/predict/reads/inspect.mjs +37 -0
- package/dist/predict/reads/inspect.mjs.map +1 -0
- package/dist/predict/reads/markets.mjs +130 -0
- package/dist/predict/reads/markets.mjs.map +1 -0
- package/dist/predict/reads/parse.mjs +20 -0
- package/dist/predict/reads/parse.mjs.map +1 -0
- package/dist/predict/reads/pool.mjs +26 -0
- package/dist/predict/reads/pool.mjs.map +1 -0
- package/dist/predict/reads/positions.d.mts +12 -0
- package/dist/predict/reads/positions.d.mts.map +1 -0
- package/dist/predict/reads/positions.mjs +77 -0
- package/dist/predict/reads/positions.mjs.map +1 -0
- package/dist/predict/reads/pricing.d.mts +20 -0
- package/dist/predict/reads/pricing.d.mts.map +1 -0
- package/dist/predict/reads/pricing.mjs +43 -0
- package/dist/predict/reads/pricing.mjs.map +1 -0
- package/dist/predict/ticks.d.mts +11 -0
- package/dist/predict/ticks.d.mts.map +1 -0
- package/dist/predict/ticks.mjs +21 -0
- package/dist/predict/ticks.mjs.map +1 -0
- package/dist/predict/tx/authed.mjs +18 -0
- package/dist/predict/tx/authed.mjs.map +1 -0
- package/dist/predict/tx/common.d.mts +18 -0
- package/dist/predict/tx/common.d.mts.map +1 -0
- package/dist/predict/tx/common.mjs +52 -0
- package/dist/predict/tx/common.mjs.map +1 -0
- package/dist/predict/tx/trade.d.mts +15 -0
- package/dist/predict/tx/trade.d.mts.map +1 -0
- package/dist/predict/tx/trade.mjs +86 -0
- package/dist/predict/tx/trade.mjs.map +1 -0
- package/dist/predict/units.d.mts +11 -0
- package/dist/predict/units.d.mts.map +1 -0
- package/dist/predict/units.mjs +44 -0
- package/dist/predict/units.mjs.map +1 -0
- package/dist/queries/accountQueries.mjs +0 -1
- package/dist/queries/accountQueries.mjs.map +1 -1
- package/dist/queries/orderQueries.mjs +0 -1
- package/dist/queries/orderQueries.mjs.map +1 -1
- package/dist/queries/registryQueries.mjs +0 -1
- package/dist/queries/registryQueries.mjs.map +1 -1
- package/dist/sessions.d.mts +244 -0
- package/dist/sessions.d.mts.map +1 -0
- package/dist/sessions.mjs +291 -0
- package/dist/sessions.mjs.map +1 -0
- 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/marginLiquidations.d.mts +3 -3
- package/dist/transactions/marginMaintainer.d.mts +5 -5
- package/dist/transactions/marginManager.d.mts +32 -32
- package/dist/transactions/marginPool.d.mts +18 -18
- package/dist/transactions/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 +25 -4
- package/src/account.ts +239 -0
- package/src/bcs/integers.ts +35 -0
- package/src/contracts/account/account.ts +706 -0
- package/src/contracts/account/account_events.ts +64 -0
- package/src/contracts/account/account_registry.ts +468 -0
- package/src/contracts/account/config-arguments.ts +8 -0
- package/src/contracts/account/deps/sui/bag.ts +42 -0
- package/src/contracts/deepbook_predict/admin.ts +44 -0
- package/src/contracts/deepbook_predict/builder_code.ts +155 -0
- package/src/contracts/deepbook_predict/builder_code_events.ts +34 -0
- package/src/contracts/deepbook_predict/config-arguments.ts +11 -0
- package/src/contracts/deepbook_predict/config_events.ts +140 -0
- package/src/contracts/deepbook_predict/deps/fixed_math/i64.ts +21 -0
- package/src/contracts/deepbook_predict/deps/sui/balance.ts +25 -0
- package/src/contracts/deepbook_predict/deps/sui/coin.ts +20 -0
- package/src/contracts/deepbook_predict/deps/sui/table.ts +37 -0
- package/src/contracts/deepbook_predict/deps/sui/vec_set.ts +22 -0
- package/src/contracts/deepbook_predict/ewma.ts +26 -0
- package/src/contracts/deepbook_predict/ewma_config.ts +28 -0
- package/src/contracts/deepbook_predict/expiry_cash.ts +24 -0
- package/src/contracts/deepbook_predict/expiry_market.ts +1549 -0
- package/src/contracts/deepbook_predict/lp_book.ts +105 -0
- package/src/contracts/deepbook_predict/market_lifecycle_cap.ts +75 -0
- package/src/contracts/deepbook_predict/market_manager.ts +218 -0
- package/src/contracts/deepbook_predict/order.ts +24 -0
- package/src/contracts/deepbook_predict/order_events.ts +129 -0
- package/src/contracts/deepbook_predict/pause_cap.ts +68 -0
- package/src/contracts/deepbook_predict/plp.ts +987 -0
- package/src/contracts/deepbook_predict/pool_accounting.ts +79 -0
- package/src/contracts/deepbook_predict/predict_account.ts +180 -0
- package/src/contracts/deepbook_predict/pricing.ts +124 -0
- package/src/contracts/deepbook_predict/pricing_config.ts +41 -0
- package/src/contracts/deepbook_predict/protocol_config.ts +1066 -0
- package/src/contracts/deepbook_predict/range_codec.ts +53 -0
- package/src/contracts/deepbook_predict/registry.ts +694 -0
- package/src/contracts/deepbook_predict/strike_exposure.ts +77 -0
- package/src/contracts/deepbook_predict/strike_exposure_config.ts +46 -0
- package/src/contracts/deepbook_predict/strike_payout_tree.ts +89 -0
- package/src/contracts/deepbook_predict/vault_events.ts +222 -0
- package/src/contracts/deepbook_sessions/config-arguments.ts +8 -0
- package/src/contracts/deepbook_sessions/deps/sui/vec_map.ts +33 -0
- package/src/contracts/deepbook_sessions/session_config.ts +130 -0
- package/src/contracts/deepbook_sessions/sessions.ts +663 -0
- package/src/contracts/propbook/block_scholes_store.ts +842 -0
- package/src/contracts/propbook/deps/sui/table.ts +37 -0
- package/src/contracts/propbook/oracle_lane.ts +170 -0
- package/src/contracts/propbook/pyth_feed.ts +414 -0
- package/src/contracts/propbook/registry.ts +596 -0
- package/src/deployments/index.ts +73 -0
- package/src/deployments/testnet.ts +107 -0
- package/src/deployments/types.ts +81 -0
- package/src/index.ts +5 -0
- package/src/predict/client.ts +941 -0
- package/src/predict/config/generated.ts +39 -0
- package/src/predict/config/index.ts +25 -0
- package/src/predict/config/testnet.ts +27 -0
- package/src/predict/config/types.ts +52 -0
- package/src/predict/decode.ts +476 -0
- package/src/predict/errors.ts +83 -0
- package/src/predict/index.ts +94 -0
- package/src/predict/pricing.ts +199 -0
- package/src/predict/reads/balances.ts +55 -0
- package/src/predict/reads/inspect.ts +78 -0
- package/src/predict/reads/markets.ts +222 -0
- package/src/predict/reads/parse.ts +30 -0
- package/src/predict/reads/pool.ts +37 -0
- package/src/predict/reads/positions.ts +144 -0
- package/src/predict/reads/pricing.ts +79 -0
- package/src/predict/ticks.ts +42 -0
- package/src/predict/tx/authed.ts +20 -0
- package/src/predict/tx/common.ts +92 -0
- package/src/predict/tx/trade.ts +183 -0
- package/src/predict/units.ts +49 -0
- package/src/sessions.ts +471 -0
- package/dist/types/bcs.mjs +0 -7
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
4
|
+
import { type GeneratedConfig } from '../config/generated.js';
|
|
5
|
+
import { type UnderlyingConfig } from '../config/index.js';
|
|
6
|
+
import { PredictMoveError } from '../errors.js';
|
|
7
|
+
import { POS_INF_TICK } from '../ticks.js';
|
|
8
|
+
import { loadLivePricer, type MarketFeeds } from '../tx/trade.js';
|
|
9
|
+
import * as expiryMarket from '../../contracts/deepbook_predict/expiry_market.js';
|
|
10
|
+
import * as plp from '../../contracts/deepbook_predict/plp.js';
|
|
11
|
+
import * as pricing from '../../contracts/deepbook_predict/pricing.js';
|
|
12
|
+
import * as rangeCodec from '../../contracts/deepbook_predict/range_codec.js';
|
|
13
|
+
import * as registry from '../../contracts/deepbook_predict/registry.js';
|
|
14
|
+
import { inspectReturns, type ReadClient } from './inspect.js';
|
|
15
|
+
import { parseOptionalId, parseOptionalU64, parseU64LE, parseVectorOfIds } from './parse.js';
|
|
16
|
+
|
|
17
|
+
// On-chain ids of the pool's active (live, not-yet-settled) expiry markets.
|
|
18
|
+
// `plp::active_expiry_markets(vault)` — see packages/predict/sources/plp/plp.move:179.
|
|
19
|
+
export async function activeMarketIds(
|
|
20
|
+
client: ReadClient,
|
|
21
|
+
config: GeneratedConfig,
|
|
22
|
+
): Promise<string[]> {
|
|
23
|
+
const tx = new Transaction();
|
|
24
|
+
tx.add(plp.activeExpiryMarkets({ config }));
|
|
25
|
+
const [cmd0] = await inspectReturns(client, tx);
|
|
26
|
+
return parseVectorOfIds(cmd0[0]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The expiry market id for one underlying at one expiry, or null if none exists.
|
|
30
|
+
// `registry::expiry_market_id(registry, propbook_underlying_id: u32, expiry: u64):
|
|
31
|
+
// Option<ID>` — see packages/predict/sources/registry/registry.move:53.
|
|
32
|
+
export async function expiryMarketId(
|
|
33
|
+
client: ReadClient,
|
|
34
|
+
config: GeneratedConfig,
|
|
35
|
+
underlying: UnderlyingConfig,
|
|
36
|
+
expiryMs: bigint,
|
|
37
|
+
): Promise<string | null> {
|
|
38
|
+
const tx = new Transaction();
|
|
39
|
+
tx.add(
|
|
40
|
+
registry.expiryMarketId({
|
|
41
|
+
config,
|
|
42
|
+
arguments: { propbookUnderlyingId: underlying.propbookUnderlyingId, expiry: expiryMs },
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
const [cmd0] = await inspectReturns(client, tx);
|
|
46
|
+
return parseOptionalId(cmd0[0]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface MarketState {
|
|
50
|
+
expiryMs: bigint;
|
|
51
|
+
tickSizeRaw: bigint;
|
|
52
|
+
/**
|
|
53
|
+
* The COARSER raw-price step new finite mint boundaries must align to
|
|
54
|
+
* (`expiry_market::admission_tick_size`). A numeric strike must be a whole
|
|
55
|
+
* multiple of this — the fine `tickSizeRaw` grid alone is not sufficient — or
|
|
56
|
+
* the chain aborts `EInvalidAdmissionTick`. The market's reference tick is the
|
|
57
|
+
* one finite boundary allowed to bypass it.
|
|
58
|
+
*/
|
|
59
|
+
admissionTickSizeRaw: bigint;
|
|
60
|
+
mintPaused: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* The reference fine-grid tick (Polymarket-style anchor strike: derived
|
|
63
|
+
* on-chain from the exact previous-window oracle observation), or null while
|
|
64
|
+
* the keeper has not seeded it. Reference PRICE raw = tick * tickSizeRaw.
|
|
65
|
+
*/
|
|
66
|
+
referenceTickRaw: bigint | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The per-market state getters, in fixed order. `expiry_market::{expiry,
|
|
70
|
+
// tick_size, mint_paused, reference_tick}` — see
|
|
71
|
+
// packages/predict/sources/expiry_market.move:{101,177,259,187}. reference_tick
|
|
72
|
+
// returns Option (no abort risk). settlement is read separately via
|
|
73
|
+
// `settlementPrice` (its own non-batched getter below).
|
|
74
|
+
const STATE_FNS = [
|
|
75
|
+
expiryMarket.expiry,
|
|
76
|
+
expiryMarket.tickSize,
|
|
77
|
+
expiryMarket.admissionTickSize,
|
|
78
|
+
expiryMarket.mintPaused,
|
|
79
|
+
expiryMarket.referenceTick,
|
|
80
|
+
] as const;
|
|
81
|
+
|
|
82
|
+
function parseStateAt(cmds: Uint8Array[][], base: number): MarketState {
|
|
83
|
+
return {
|
|
84
|
+
expiryMs: parseU64LE(cmds[base][0]),
|
|
85
|
+
tickSizeRaw: parseU64LE(cmds[base + 1][0]),
|
|
86
|
+
admissionTickSizeRaw: parseU64LE(cmds[base + 2][0]),
|
|
87
|
+
mintPaused: (cmds[base + 3][0][0] ?? 0) !== 0, // BCS bool: 1 byte
|
|
88
|
+
referenceTickRaw: parseOptionalU64(cmds[base + 4][0]),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function marketState(
|
|
93
|
+
client: ReadClient,
|
|
94
|
+
config: GeneratedConfig,
|
|
95
|
+
marketId: string,
|
|
96
|
+
): Promise<MarketState> {
|
|
97
|
+
const [state] = await marketStates(client, config, [marketId]);
|
|
98
|
+
return state;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Batched marketState for N markets in ONE PTB (STATE_FNS.length commands per
|
|
102
|
+
// market, same order). Returns states aligned with `marketIds`.
|
|
103
|
+
export async function marketStates(
|
|
104
|
+
client: ReadClient,
|
|
105
|
+
config: GeneratedConfig,
|
|
106
|
+
marketIds: readonly string[],
|
|
107
|
+
): Promise<MarketState[]> {
|
|
108
|
+
if (marketIds.length === 0) return [];
|
|
109
|
+
const tx = new Transaction();
|
|
110
|
+
for (const id of marketIds) {
|
|
111
|
+
for (const fn of STATE_FNS) {
|
|
112
|
+
tx.add(fn({ config, arguments: { market: id } }));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const cmds = await inspectReturns(client, tx);
|
|
116
|
+
return marketIds.map((_, i) => parseStateAt(cmds, STATE_FNS.length * i));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Anonymous both-sides pricing for one strike: the chain's own probability for
|
|
120
|
+
// (strike, +inf] and (-inf, strike]. Deployed `pricing::range_price` takes typed
|
|
121
|
+
// `range_codec::Strike`s (NOT raw u64) — each boundary is built via
|
|
122
|
+
// `range_codec::strike_from_tick(tick, tick_size)`, which maps tick 0 → -inf,
|
|
123
|
+
// POS_INF_TICK → +inf, and any finite tick → tick*tick_size. `range_price` is a
|
|
124
|
+
// public fun on the deployed package. Both sides read the SAME pricer in one PTB, so
|
|
125
|
+
// `down` is the chain's number, not 1 − up.
|
|
126
|
+
export async function rangePrices(
|
|
127
|
+
client: ReadClient,
|
|
128
|
+
config: GeneratedConfig,
|
|
129
|
+
marketId: string,
|
|
130
|
+
feeds: MarketFeeds,
|
|
131
|
+
strikeRaw: bigint,
|
|
132
|
+
tickSizeRaw: bigint,
|
|
133
|
+
): Promise<{ upRaw: bigint; downRaw: bigint }> {
|
|
134
|
+
const tx = new Transaction();
|
|
135
|
+
const pricer = tx.add(loadLivePricer(config, { expiryMarketId: marketId, ...feeds }));
|
|
136
|
+
// strikeRaw is a whole tick multiple (the caller validates divisibility), so the
|
|
137
|
+
// finite boundary is `strike_from_tick(strikeRaw / tickSize, tickSize)`.
|
|
138
|
+
const strikeTick = strikeRaw / tickSizeRaw;
|
|
139
|
+
const mkStrike = (tick: bigint) =>
|
|
140
|
+
tx.add(rangeCodec.strikeFromTick({ config, arguments: { tick, tickSize: tickSizeRaw } }));
|
|
141
|
+
const strike = mkStrike(strikeTick);
|
|
142
|
+
const posInf = mkStrike(POS_INF_TICK);
|
|
143
|
+
const negInf = mkStrike(0n);
|
|
144
|
+
// UP: (strike, +inf], then DOWN: (-inf, strike] — the last two commands.
|
|
145
|
+
tx.add(pricing.rangePrice({ config, arguments: { pricer, lower: strike, higher: posInf } }));
|
|
146
|
+
tx.add(pricing.rangePrice({ config, arguments: { pricer, lower: negInf, higher: strike } }));
|
|
147
|
+
const cmds = await inspectReturns(client, tx);
|
|
148
|
+
return {
|
|
149
|
+
upRaw: parseU64LE(cmds[cmds.length - 2][0]),
|
|
150
|
+
downRaw: parseU64LE(cmds[cmds.length - 1][0]),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Fresh single read of the reference tick — used by mint-at-reference, which
|
|
155
|
+
// must not trust a cached state (the reference is unset early in a window
|
|
156
|
+
// until the keeper seeds it).
|
|
157
|
+
export async function referenceTick(
|
|
158
|
+
client: ReadClient,
|
|
159
|
+
config: GeneratedConfig,
|
|
160
|
+
marketId: string,
|
|
161
|
+
): Promise<bigint | null> {
|
|
162
|
+
const tx = new Transaction();
|
|
163
|
+
tx.add(expiryMarket.referenceTick({ config, arguments: { market: marketId } }));
|
|
164
|
+
const [cmd0] = await inspectReturns(client, tx);
|
|
165
|
+
return parseOptionalU64(cmd0[0]);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// The recorded settlement price, or null while the market is unsettled.
|
|
169
|
+
//
|
|
170
|
+
// On the deployed package `expiry_market::settlement_price` is public and
|
|
171
|
+
// `destroy_some`s the stored Option — callable here only because simulate runs with
|
|
172
|
+
// checksEnabled:false, and it aborts in std::option (EOPTION_NOT_SET) when the
|
|
173
|
+
// market has not settled; we map exactly that abort (and the public
|
|
174
|
+
// EMarketNotSettled variant, should a future package guard it directly) to null.
|
|
175
|
+
// (A non-aborting `try_settlement_price` also exists on-chain if this ever wants to
|
|
176
|
+
// drop the abort-catch.)
|
|
177
|
+
export async function settlementPrice(
|
|
178
|
+
client: ReadClient,
|
|
179
|
+
config: GeneratedConfig,
|
|
180
|
+
marketId: string,
|
|
181
|
+
): Promise<bigint | null> {
|
|
182
|
+
const tx = new Transaction();
|
|
183
|
+
tx.add(expiryMarket.settlementPrice({ config, arguments: { market: marketId } }));
|
|
184
|
+
try {
|
|
185
|
+
const [cmd0] = await inspectReturns(client, tx);
|
|
186
|
+
return parseU64LE(cmd0[0]);
|
|
187
|
+
} catch (e) {
|
|
188
|
+
if (
|
|
189
|
+
e instanceof PredictMoveError &&
|
|
190
|
+
(e.module === 'option' ||
|
|
191
|
+
(e.module === 'expiry_market' && e.abortName === 'EMarketNotSettled'))
|
|
192
|
+
) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
throw e;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// A market's current NAV mark (the per-expiry recoverable value the flush prices
|
|
200
|
+
// against). Loads a fresh live pricer, then reads `current_nav(market, &pricer)` —
|
|
201
|
+
// see packages/predict/sources/expiry_market.move:236. `Pricer` has copy+drop, so
|
|
202
|
+
// the unconsumed borrow is fine in a read-only inspect.
|
|
203
|
+
export async function currentNav(
|
|
204
|
+
client: ReadClient,
|
|
205
|
+
config: GeneratedConfig,
|
|
206
|
+
marketId: string,
|
|
207
|
+
underlying: UnderlyingConfig,
|
|
208
|
+
): Promise<bigint> {
|
|
209
|
+
const tx = new Transaction();
|
|
210
|
+
const pricer = tx.add(
|
|
211
|
+
loadLivePricer(config, {
|
|
212
|
+
expiryMarketId: marketId,
|
|
213
|
+
pythFeed: underlying.pythFeed,
|
|
214
|
+
blockScholesValueStore: underlying.blockScholesValueStore,
|
|
215
|
+
blockScholesSviStore: underlying.blockScholesSviStore,
|
|
216
|
+
}),
|
|
217
|
+
);
|
|
218
|
+
tx.add(expiryMarket.currentNav({ config, arguments: { market: marketId, pricer } }));
|
|
219
|
+
const cmds = await inspectReturns(client, tx);
|
|
220
|
+
// current_nav is the last command; load_live_pricer precedes it.
|
|
221
|
+
return parseU64LE(cmds[cmds.length - 1][0]);
|
|
222
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// BCS decoders for the return values of on-chain reads, built on the
|
|
4
|
+
// `@mysten/sui/bcs` codec so the read layer decodes exactly the on-chain Move ABI
|
|
5
|
+
// (u64 LE, vector<ID>, Option) with no hand-rolled byte walking. Round-tripped
|
|
6
|
+
// against `@mysten/sui/bcs` in tests/reads.test.ts.
|
|
7
|
+
|
|
8
|
+
import { bcs } from '@mysten/sui/bcs';
|
|
9
|
+
|
|
10
|
+
// BCS u64 → bigint. `bcs.u64()` parses to a decimal string.
|
|
11
|
+
export function parseU64LE(bytes: Uint8Array): bigint {
|
|
12
|
+
return BigInt(bcs.u64().parse(bytes));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// BCS vector<ID> / vector<address> → full-length 0x lowercase ids
|
|
16
|
+
// (`bcs.Address` already yields normalized ids).
|
|
17
|
+
export function parseVectorOfIds(bytes: Uint8Array): string[] {
|
|
18
|
+
return bcs.vector(bcs.Address).parse(bytes);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// BCS Option<u64>: None → null, Some(x) → x.
|
|
22
|
+
export function parseOptionalU64(bytes: Uint8Array): bigint | null {
|
|
23
|
+
const v = bcs.option(bcs.u64()).parse(bytes);
|
|
24
|
+
return v == null ? null : BigInt(v);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// BCS Option<ID>: None → null, Some(id) → normalized 0x id.
|
|
28
|
+
export function parseOptionalId(bytes: Uint8Array): string | null {
|
|
29
|
+
return bcs.option(bcs.Address).parse(bytes);
|
|
30
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
4
|
+
import { type GeneratedConfig } from '../config/generated.js';
|
|
5
|
+
import * as plp from '../../contracts/deepbook_predict/plp.js';
|
|
6
|
+
import { inspectReturns, type ReadClient } from './inspect.js';
|
|
7
|
+
import { parseU64LE } from './parse.js';
|
|
8
|
+
|
|
9
|
+
export interface PoolStats {
|
|
10
|
+
plpTotalSupply: bigint;
|
|
11
|
+
idleBalance: bigint;
|
|
12
|
+
supplyRequestsPending: bigint;
|
|
13
|
+
withdrawRequestsPending: bigint;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// The pool's four u64 vault stats batched into one PTB (command order fixed below).
|
|
17
|
+
// `plp::{plp_total_supply, idle_balance, supply_requests_pending,
|
|
18
|
+
// withdraw_requests_pending}(vault)` — see
|
|
19
|
+
// packages/predict/sources/plp/plp.move:{164,149,169,174}.
|
|
20
|
+
export async function poolStats(client: ReadClient, config: GeneratedConfig): Promise<PoolStats> {
|
|
21
|
+
const tx = new Transaction();
|
|
22
|
+
for (const fn of [
|
|
23
|
+
plp.plpTotalSupply,
|
|
24
|
+
plp.idleBalance,
|
|
25
|
+
plp.supplyRequestsPending,
|
|
26
|
+
plp.withdrawRequestsPending,
|
|
27
|
+
]) {
|
|
28
|
+
tx.add(fn({ config }));
|
|
29
|
+
}
|
|
30
|
+
const cmds = await inspectReturns(client, tx);
|
|
31
|
+
return {
|
|
32
|
+
plpTotalSupply: parseU64LE(cmds[0][0]),
|
|
33
|
+
idleBalance: parseU64LE(cmds[1][0]),
|
|
34
|
+
supplyRequestsPending: parseU64LE(cmds[2][0]),
|
|
35
|
+
withdrawRequestsPending: parseU64LE(cmds[3][0]),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { bcs } from '@mysten/sui/bcs';
|
|
4
|
+
import type { ClientWithCoreApi } from '@mysten/sui/client';
|
|
5
|
+
import { deriveDynamicFieldID, normalizeSuiAddress } from '@mysten/sui/utils';
|
|
6
|
+
import { type GeneratedConfig } from '../config/generated.js';
|
|
7
|
+
import { deriveAccountWrapperIdFrom } from '../tx/common.js';
|
|
8
|
+
import { AccountWrapper } from '../../account.js';
|
|
9
|
+
import { PositionKey, PredictData } from '../../contracts/deepbook_predict/predict_account.js';
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Chain-only position enumeration.
|
|
13
|
+
//
|
|
14
|
+
// Every open position is tracked under the owner's account:
|
|
15
|
+
// `predict_account::PredictData.positions` is a
|
|
16
|
+
// `Table<PositionKey{expiry_market_id, order_id}, Position>` — and Table
|
|
17
|
+
// entries are dynamic fields, so the KEYS (everything redeem/claim need)
|
|
18
|
+
// arrive directly from a dynamic-field listing. No indexer, no simulation.
|
|
19
|
+
//
|
|
20
|
+
// The walk (all parsing is exact BCS via `include: {content: true}`; the account
|
|
21
|
+
// and PredictData struct layouts come from the generated `contracts/*` MoveStructs
|
|
22
|
+
// so they can't drift from the deployed `account`/`predict_account` sources):
|
|
23
|
+
// 1. wrapper object (id derived client-side) → account UID
|
|
24
|
+
// 2. derived DataKey<PredictApp> field object → positions Table id
|
|
25
|
+
// 3. listDynamicFields(table) → PositionKey per entry
|
|
26
|
+
// Steps 1-2 resolve ids that are immutable once created — cache them per
|
|
27
|
+
// owner (the facade does) and steady state is ONE call per page of positions.
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
// sui::dynamic_field::Field<DataKey<PredictApp>, PredictData>. DataKey is
|
|
31
|
+
// source-empty, but Move inserts a hidden `dummy_field: bool` into empty
|
|
32
|
+
// structs — so the name occupies ONE zero byte between id and value (and the
|
|
33
|
+
// same byte is the derived-field key, below). The `value` uses the generated
|
|
34
|
+
// `PredictData` layout so it tracks the deployed struct.
|
|
35
|
+
const PredictDataFieldBcs = bcs.struct('Field<DataKey,PredictData>', {
|
|
36
|
+
id: bcs.Address,
|
|
37
|
+
name: bcs.bool(), // DataKey's hidden dummy_field
|
|
38
|
+
value: PredictData,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/** One open position — the coordinates redeem/claim/hasPosition take. */
|
|
42
|
+
export interface OpenPosition {
|
|
43
|
+
marketId: string;
|
|
44
|
+
orderId: bigint;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Resolved-once ids for an owner's position store (cache these). */
|
|
48
|
+
export interface PositionsHandle {
|
|
49
|
+
accountUid: string;
|
|
50
|
+
/** Null until the account's Predict data exists (first trade/builder-code). */
|
|
51
|
+
positionsTableId: string | null;
|
|
52
|
+
/** Open-position count at resolution time (from the Table's size). */
|
|
53
|
+
positionCount: bigint;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function contentOf(client: ClientWithCoreApi, objectId: string): Promise<Uint8Array | null> {
|
|
57
|
+
try {
|
|
58
|
+
const { object } = await client.core.getObject({ objectId, include: { content: true } });
|
|
59
|
+
return object.content ?? null;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
// Only a genuinely absent object means "no positions" (never-onboarded
|
|
62
|
+
// owner, or no Predict data yet). Anything else — transport failures,
|
|
63
|
+
// rate limits — must surface, not silently read as an empty portfolio.
|
|
64
|
+
if (/not.?found|does not exist|deleted|NOT_FOUND/i.test(String(e))) return null;
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resolve the immutable id chain for an owner's positions: wrapper → account
|
|
71
|
+
* UID → PredictData → positions Table. Returns null when the owner has never
|
|
72
|
+
* created a Predict account.
|
|
73
|
+
*/
|
|
74
|
+
export async function resolvePositionsTable(
|
|
75
|
+
client: ClientWithCoreApi,
|
|
76
|
+
config: GeneratedConfig,
|
|
77
|
+
owner: string,
|
|
78
|
+
): Promise<PositionsHandle | null> {
|
|
79
|
+
const wrapperContent = await contentOf(client, deriveAccountWrapperIdFrom(config, owner));
|
|
80
|
+
if (!wrapperContent) return null;
|
|
81
|
+
const accountUid = normalizeSuiAddress(AccountWrapper.parse(wrapperContent).account.account_id);
|
|
82
|
+
|
|
83
|
+
// The PredictData field id is derivable — no listing needed for this hop.
|
|
84
|
+
const dataFieldId = deriveDynamicFieldID(
|
|
85
|
+
accountUid,
|
|
86
|
+
`${config.accountPackageId}::account::DataKey<${config.predictPackageId}::predict_account::PredictApp>`,
|
|
87
|
+
new Uint8Array([0]), // DataKey's hidden dummy_field: bool = false
|
|
88
|
+
);
|
|
89
|
+
const fieldContent = await contentOf(client, dataFieldId);
|
|
90
|
+
if (!fieldContent) return { accountUid, positionsTableId: null, positionCount: 0n };
|
|
91
|
+
|
|
92
|
+
const data = PredictDataFieldBcs.parse(fieldContent).value;
|
|
93
|
+
return {
|
|
94
|
+
accountUid,
|
|
95
|
+
positionsTableId: normalizeSuiAddress(data.positions.id),
|
|
96
|
+
positionCount: data.positions.size,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* List open positions from a resolved positions Table: one call per page,
|
|
102
|
+
* keys parsed from the dynamic-field NAMES (no per-entry fetches).
|
|
103
|
+
*/
|
|
104
|
+
export async function positionsFromTable(
|
|
105
|
+
client: ClientWithCoreApi,
|
|
106
|
+
positionsTableId: string,
|
|
107
|
+
opts: { limit?: number; maxPages?: number } = {},
|
|
108
|
+
): Promise<OpenPosition[]> {
|
|
109
|
+
const limit = opts.limit ?? 1000;
|
|
110
|
+
const maxPages = opts.maxPages ?? 10;
|
|
111
|
+
const out: OpenPosition[] = [];
|
|
112
|
+
let cursor: string | undefined = undefined;
|
|
113
|
+
for (let page = 0; page < maxPages; page++) {
|
|
114
|
+
const res = await client.core.listDynamicFields({
|
|
115
|
+
parentId: positionsTableId,
|
|
116
|
+
limit,
|
|
117
|
+
cursor,
|
|
118
|
+
});
|
|
119
|
+
for (const entry of res.dynamicFields) {
|
|
120
|
+
const key = PositionKey.parse(entry.name.bcs);
|
|
121
|
+
out.push({
|
|
122
|
+
marketId: normalizeSuiAddress(key.expiry_market_id),
|
|
123
|
+
orderId: key.order_id,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (!res.hasNextPage || !res.cursor) return out;
|
|
127
|
+
cursor = res.cursor;
|
|
128
|
+
}
|
|
129
|
+
throw new Error(
|
|
130
|
+
`positions listing exceeded ${maxPages} pages (${out.length} so far) — raise maxPages`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Convenience: resolve + list in one call (uncached; the facade caches). */
|
|
135
|
+
export async function positions(
|
|
136
|
+
client: ClientWithCoreApi,
|
|
137
|
+
config: GeneratedConfig,
|
|
138
|
+
owner: string,
|
|
139
|
+
opts: { limit?: number; maxPages?: number } = {},
|
|
140
|
+
): Promise<OpenPosition[]> {
|
|
141
|
+
const handle = await resolvePositionsTable(client, config, owner);
|
|
142
|
+
if (!handle?.positionsTableId) return [];
|
|
143
|
+
return positionsFromTable(client, handle.positionsTableId, opts);
|
|
144
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
4
|
+
import { type GeneratedConfig } from '../config/generated.js';
|
|
5
|
+
import { Pricer } from '../../contracts/deepbook_predict/pricing.js';
|
|
6
|
+
import type { PricerInputs, Svi } from '../pricing.js';
|
|
7
|
+
import { loadLivePricer, type MarketFeeds } from '../tx/trade.js';
|
|
8
|
+
import { inspectReturns, type ReadClient } from './inspect.js';
|
|
9
|
+
|
|
10
|
+
// The chain's fixed-point scales for the rolled `PricingSVI` (see the generated
|
|
11
|
+
// `Pricer`/`PricingSVI` struct): forward and rho/m/sigma at 1e9; the rolled `a`/`b` land
|
|
12
|
+
// at 1e18 (roll_down multiplies the 1e9 raw by an extra 1e9). Converting to `number`
|
|
13
|
+
// (float) is deliberate — this is a display pricer; a is a variance ~O(1e-2), so f64's
|
|
14
|
+
// ~15 significant digits are ample and, per pricing.ts, more precise than the chain's
|
|
15
|
+
// fixed point on the short-dated surfaces this prices.
|
|
16
|
+
const FORWARD_SCALE = 1e9;
|
|
17
|
+
const AB_SCALE = 1e18;
|
|
18
|
+
const RMS_SCALE = 1e9; // rho, m, sigma
|
|
19
|
+
|
|
20
|
+
const i64 = (v: { magnitude: string | number | bigint; is_negative: boolean }): number =>
|
|
21
|
+
(v.is_negative ? -1 : 1) * Number(v.magnitude);
|
|
22
|
+
|
|
23
|
+
/** A resolved pricer snapshot read from the chain: the decimal forward + rolled SVI the
|
|
24
|
+
* client-side math consumes, plus the oracle source timestamps behind it (ms; for
|
|
25
|
+
* staleness display — Pyth is 0 when no usable spot existed). The Block-Scholes entries are
|
|
26
|
+
* batch ENVELOPE times (what freshness and the SVI roll-down anchor on), not model times. */
|
|
27
|
+
export interface PricerSnapshot extends PricerInputs {
|
|
28
|
+
sources: {
|
|
29
|
+
pythSpotMs: number;
|
|
30
|
+
blockScholesSpotMs: number;
|
|
31
|
+
blockScholesForwardMs: number;
|
|
32
|
+
blockScholesSviMs: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Decode a `Pricer` (already forward-resolved + roll-down-applied on-chain) into decimal
|
|
37
|
+
// `PricerInputs`. Signed fields (`a`, `rho`, `m`) carry the magnitude/flag pair the chain
|
|
38
|
+
// uses; `b`/`sigma` are non-negative.
|
|
39
|
+
function decodePricer(pricer: ReturnType<typeof Pricer.parse>): PricerSnapshot {
|
|
40
|
+
const s = pricer.svi;
|
|
41
|
+
const svi: Svi = {
|
|
42
|
+
a: ((s.a_is_negative ? -1 : 1) * Number(s.a_magnitude)) / AB_SCALE,
|
|
43
|
+
b: Number(s.b) / AB_SCALE,
|
|
44
|
+
rho: i64(s.rho) / RMS_SCALE,
|
|
45
|
+
m: i64(s.m) / RMS_SCALE,
|
|
46
|
+
sigma: Number(s.sigma) / RMS_SCALE,
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
forward: Number(pricer.forward) / FORWARD_SCALE,
|
|
50
|
+
svi,
|
|
51
|
+
sources: {
|
|
52
|
+
pythSpotMs: Number(pricer.pyth_spot_source_timestamp_ms),
|
|
53
|
+
blockScholesSpotMs: Number(pricer.block_scholes_spot_source_timestamp_ms),
|
|
54
|
+
blockScholesForwardMs: Number(pricer.block_scholes_forward_source_timestamp_ms),
|
|
55
|
+
blockScholesSviMs: Number(pricer.block_scholes_svi_source_timestamp_ms),
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Read one live pricer snapshot for `marketId`: a single simulate of
|
|
61
|
+
// `load_live_pricer` — the chain reads the oracle feeds, picks the forward
|
|
62
|
+
// (Pyth-vs-Block-Scholes admin policy + freshness), and rolls the SVI down to now, then
|
|
63
|
+
// returns the whole `Pricer` by value (copy+drop), whose BCS we decode. One round trip;
|
|
64
|
+
// then a `boardPricer` prices every strike locally.
|
|
65
|
+
//
|
|
66
|
+
// `load_live_pricer` ABORTS (a typed PredictMoveError) when the market is expired, a feed
|
|
67
|
+
// is stale, or the surface fails the pricing-safe envelope — i.e. exactly when the chain
|
|
68
|
+
// itself cannot quote. Callers surface that the same way `read.price` does.
|
|
69
|
+
export async function readPricerSnapshot(
|
|
70
|
+
client: ReadClient,
|
|
71
|
+
config: GeneratedConfig,
|
|
72
|
+
marketId: string,
|
|
73
|
+
feeds: MarketFeeds,
|
|
74
|
+
): Promise<PricerSnapshot> {
|
|
75
|
+
const tx = new Transaction();
|
|
76
|
+
tx.add(loadLivePricer(config, { expiryMarketId: marketId, ...feeds }));
|
|
77
|
+
const [cmd0] = await inspectReturns(client, tx);
|
|
78
|
+
return decodePricer(Pricer.parse(cmd0[0]));
|
|
79
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { PredictInputError } from './errors.js';
|
|
4
|
+
|
|
5
|
+
const TICK_BITS = 30n;
|
|
6
|
+
|
|
7
|
+
/** +inf sentinel tick: the upper bound of an UP range. */
|
|
8
|
+
export const POS_INF_TICK = (1n << TICK_BITS) - 1n;
|
|
9
|
+
|
|
10
|
+
export type Side = 'up' | 'down';
|
|
11
|
+
|
|
12
|
+
// Convert a raw binary-range strike to the `(lower_tick, higher_tick)` pair the
|
|
13
|
+
// `mint` entrypoint takes directly (there is no standalone packed range key).
|
|
14
|
+
// An UP order is `(strike, +inf)` -> lower_tick = strike/tick_size, higher_tick =
|
|
15
|
+
// POS_INF_TICK; a DOWN order is `(-inf, strike)` -> lower_tick = 0 (neg-inf),
|
|
16
|
+
// higher_tick = strike/tick_size.
|
|
17
|
+
export function binaryRangeTicks(
|
|
18
|
+
strikeRaw: bigint,
|
|
19
|
+
side: Side,
|
|
20
|
+
tickSize: bigint,
|
|
21
|
+
): { lowerTick: bigint; higherTick: bigint } {
|
|
22
|
+
// Anything not exactly 'up' used to fall through to DOWN, byte-identical to a real
|
|
23
|
+
// down mint — no build error, no simulate error, no chain abort. `side` arrives from UI
|
|
24
|
+
// state, JSON, or a DB column at runtime, where the literal type does not protect.
|
|
25
|
+
if (side !== 'up' && side !== 'down') {
|
|
26
|
+
throw new PredictInputError(`side must be 'up' or 'down', got ${JSON.stringify(side)}`);
|
|
27
|
+
}
|
|
28
|
+
const tick = strikeRaw / tickSize;
|
|
29
|
+
if (tick * tickSize !== strikeRaw) {
|
|
30
|
+
throw new PredictInputError(`strike ${strikeRaw} is not a whole tick multiple of ${tickSize}`);
|
|
31
|
+
}
|
|
32
|
+
if (tick <= 0n || tick >= POS_INF_TICK) {
|
|
33
|
+
throw new PredictInputError(
|
|
34
|
+
`strike tick ${tick} outside the finite tick domain (1..POS_INF_TICK-1)`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const isUp = side === 'up';
|
|
38
|
+
return {
|
|
39
|
+
lowerTick: isUp ? tick : 0n,
|
|
40
|
+
higherTick: isUp ? POS_INF_TICK : tick,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { accountMoveCalls as account } from '../../account.js';
|
|
4
|
+
import * as plp from '../../contracts/deepbook_predict/plp.js';
|
|
5
|
+
import * as predictAccount from '../../contracts/deepbook_predict/predict_account.js';
|
|
6
|
+
import { withAuth } from './common.js';
|
|
7
|
+
|
|
8
|
+
// Every owner-authorized single call in this SDK, declared rather than written: `withAuth`
|
|
9
|
+
// prepends the `generate_auth` command and fills the generated `auth` argument, so each of these
|
|
10
|
+
// takes exactly its generated options minus that slot. Command order is always auth → call, the
|
|
11
|
+
// call consuming the hot potato. The builder-code pair lives in the PREDICT package's
|
|
12
|
+
// `predict_account` module, not the account package.
|
|
13
|
+
export const depositFunds = withAuth(account.depositFunds);
|
|
14
|
+
export const withdrawFunds = withAuth(account.withdrawFunds);
|
|
15
|
+
export const requestSupply = withAuth(plp.requestSupply);
|
|
16
|
+
export const requestWithdraw = withAuth(plp.requestWithdraw);
|
|
17
|
+
export const cancelSupplyRequest = withAuth(plp.cancelSupplyRequest);
|
|
18
|
+
export const cancelWithdrawRequest = withAuth(plp.cancelWithdrawRequest);
|
|
19
|
+
export const setBuilderCode = withAuth(predictAccount.setBuilderCode);
|
|
20
|
+
export const unsetBuilderCode = withAuth(predictAccount.unsetBuilderCode);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import type { Transaction, TransactionArgument, TransactionResult } from '@mysten/sui/transactions';
|
|
4
|
+
import { toGeneratedConfig, type GeneratedConfig } from '../config/generated.js';
|
|
5
|
+
import type { PredictConfig } from '../config/index.js';
|
|
6
|
+
import { AccountContract, accountMoveCalls as account } from '../../account.js';
|
|
7
|
+
|
|
8
|
+
// Predict's accounts ARE the shared on-chain account primitive (`packages/account`), so the
|
|
9
|
+
// builders live in `@mysten/deepbook-v3/account` and this is the thin adapter that drives them with
|
|
10
|
+
// Predict's deployed ids. The generated thunks are still used directly by `withAuth` below, which
|
|
11
|
+
// wraps Predict's own entrypoints too — those take the same `Auth` hot potato.
|
|
12
|
+
export function accountContract(cfg: PredictConfig): AccountContract {
|
|
13
|
+
return new AccountContract({
|
|
14
|
+
accountPackageId: cfg.packages.account,
|
|
15
|
+
accountRegistry: cfg.objects.accountRegistry,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Owner authority is a hot-potato `Auth` minted from the tx sender (`ctx` is implicit in a PTB)
|
|
21
|
+
* and consumed by the very next account-loading call (`load_account_mut` inside `deposit_funds` /
|
|
22
|
+
* `withdraw_funds` / `mint` / …). It resolves to owner auth for whoever signs the transaction.
|
|
23
|
+
* See `packages/account/sources/account.move`.
|
|
24
|
+
*/
|
|
25
|
+
export function generateAuth(cfg: PredictConfig): (tx: Transaction) => TransactionResult {
|
|
26
|
+
return account.generateAuth({ config: toGeneratedConfig(cfg) });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The shape every generated binding shares: options in, one PTB command out.
|
|
30
|
+
type GeneratedCall<Options> = (options: Options) => (tx: Transaction) => TransactionResult;
|
|
31
|
+
|
|
32
|
+
// The generated options of a call that consumes the hot-potato `Auth`. Codegen types
|
|
33
|
+
// `arguments` as the named form OR a positional tuple; only the named form is used here.
|
|
34
|
+
interface AuthCallOptions {
|
|
35
|
+
arguments: { auth: TransactionArgument } | readonly unknown[];
|
|
36
|
+
config?: object;
|
|
37
|
+
package?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The named-`arguments` arm of such an options type (the tuple arm has no `auth` property).
|
|
41
|
+
type NamedArguments<Options extends AuthCallOptions> = Extract<
|
|
42
|
+
Options['arguments'],
|
|
43
|
+
{ auth: TransactionArgument }
|
|
44
|
+
>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The options {@link withAuth} leaves to the caller: the generated ones, minus the `auth`
|
|
48
|
+
* argument it supplies itself, with the projected config required (it is what mints the auth).
|
|
49
|
+
*/
|
|
50
|
+
export type WithAuthOptions<Options extends AuthCallOptions> = Omit<
|
|
51
|
+
Options,
|
|
52
|
+
'arguments' | 'config'
|
|
53
|
+
> & {
|
|
54
|
+
config: GeneratedConfig;
|
|
55
|
+
arguments: Omit<NamedArguments<Options>, 'auth'>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Every owner-authorized call in this SDK is the same two commands — mint the hot-potato `Auth`,
|
|
60
|
+
* then make the generated call that consumes it. This lifts a generated binding into that pair,
|
|
61
|
+
* so such a builder is declared rather than written: `withAuth(account.depositFunds)` takes
|
|
62
|
+
* `deposit_funds`'s own options with the `auth` slot already filled.
|
|
63
|
+
*/
|
|
64
|
+
export function withAuth<Options extends AuthCallOptions>(
|
|
65
|
+
call: GeneratedCall<Options>,
|
|
66
|
+
): (options: WithAuthOptions<Options>) => (tx: Transaction) => TransactionResult {
|
|
67
|
+
return (options) => (tx) => {
|
|
68
|
+
const auth = tx.add(account.generateAuth({ config: options.config }));
|
|
69
|
+
// The one unchecked step: with `Options` still generic, TS cannot see that putting `auth`
|
|
70
|
+
// back makes the arguments whole again. Callers get the fully checked type above.
|
|
71
|
+
return tx.add(
|
|
72
|
+
call({ ...options, arguments: { ...options.arguments, auth } } as unknown as Options),
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The derivation must agree with on-chain `derive_address`, so it is owned in one place:
|
|
78
|
+
// `@mysten/deepbook-v3/account`. This projects Predict's config onto that contract.
|
|
79
|
+
export function deriveAccountWrapperIdFrom(
|
|
80
|
+
config: Pick<GeneratedConfig, 'accountRegistry' | 'accountPackageId'>,
|
|
81
|
+
owner: string,
|
|
82
|
+
): string {
|
|
83
|
+
return new AccountContract({
|
|
84
|
+
accountPackageId: config.accountPackageId,
|
|
85
|
+
accountRegistry: config.accountRegistry,
|
|
86
|
+
}).deriveAccountWrapperId(owner);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The deterministic id of an owner's canonical account wrapper — no chain read needed. */
|
|
90
|
+
export function deriveAccountWrapperId(cfg: PredictConfig, owner: string): string {
|
|
91
|
+
return deriveAccountWrapperIdFrom(toGeneratedConfig(cfg), owner);
|
|
92
|
+
}
|