From 639635d0b5cdfea89f6751d2966274ac330a9e90 Mon Sep 17 00:00:00 2001 From: Tony Lee Date: Wed, 1 Jul 2026 15:36:43 -0400 Subject: [PATCH] feat(deepbook-predict): add DeepBook Predict TypeScript SDK New standalone `@mysten/deepbook-predict` package wrapping the Predict protocol (European cash-settled range digitals): codegen bindings, the packed-u256 order-id codec, trader + LP + keeper transaction builders, on-chain + indexer queries, and the `PredictClient` facade. Pre-launch (0.0.0): Predict is not yet deployed, so `PredictConfig` takes explicit `ids`; oracle is read-only and there is no off-chain quote previewer in this first cut. Co-Authored-By: Claude Opus 4.8 --- packages/deepbook-predict/.prettierignore | 9 + packages/deepbook-predict/README.md | 30 + packages/deepbook-predict/package.json | 56 + packages/deepbook-predict/src/client.ts | 95 ++ .../src/contracts/account/account.ts | 584 +++++++++ .../src/contracts/account/account_events.ts | 63 + .../src/contracts/account/account_registry.ts | 311 +++++ .../src/contracts/account/deps/sui/bag.ts | 41 + .../src/contracts/deepbook_predict/admin.ts | 42 + .../deepbook_predict/builder_code.ts | 139 +++ .../deepbook_predict/builder_code_events.ts | 33 + .../deepbook_predict/config_events.ts | 75 ++ .../deepbook_predict/deps/fixed_math/i64.ts | 16 + .../deps/propbook/block_scholes_svi_feed.ts | 27 + .../deepbook_predict/deps/sui/balance.ts | 25 + .../deepbook_predict/deps/sui/coin.ts | 20 + .../deepbook_predict/deps/sui/table.ts | 36 + .../deepbook_predict/deps/sui/vec_set.ts | 22 + .../src/contracts/deepbook_predict/ewma.ts | 27 + .../contracts/deepbook_predict/ewma_config.ts | 27 + .../contracts/deepbook_predict/expiry_cash.ts | 26 + .../deepbook_predict/expiry_cash_config.ts | 22 + .../deepbook_predict/expiry_market.ts | 1050 +++++++++++++++++ .../deepbook_predict/liquidation_book.ts | 52 + .../src/contracts/deepbook_predict/lp_book.ts | 66 ++ .../deepbook_predict/market_lifecycle_cap.ts | 68 ++ .../deepbook_predict/market_manager.ts | 73 ++ .../src/contracts/deepbook_predict/order.ts | 25 + .../deepbook_predict/order_events.ts | 117 ++ .../contracts/deepbook_predict/pause_cap.ts | 60 + .../src/contracts/deepbook_predict/plp.ts | 981 +++++++++++++++ .../deepbook_predict/pool_accounting.ts | 73 ++ .../deepbook_predict/predict_account.ts | 278 +++++ .../src/contracts/deepbook_predict/pricing.ts | 48 + .../deepbook_predict/pricing_config.ts | 25 + .../deepbook_predict/protocol_config.ts | 674 +++++++++++ .../contracts/deepbook_predict/registry.ts | 496 ++++++++ .../deepbook_predict/stake_config.ts | 26 + .../deepbook_predict/strike_exposure.ts | 50 + .../strike_exposure_config.ts | 54 + .../deepbook_predict/strike_payout_tree.ts | 81 ++ .../deepbook_predict/vault_events.ts | 189 +++ .../propbook/block_scholes_forward_feed.ts | 332 ++++++ .../propbook/block_scholes_spot_feed.ts | 294 +++++ .../propbook/block_scholes_svi_feed.ts | 436 +++++++ .../contracts/propbook/deps/fixed_math/i64.ts | 16 + .../src/contracts/propbook/deps/sui/table.ts | 36 + .../src/contracts/propbook/oracle_lane.ts | 137 +++ .../src/contracts/propbook/pyth_feed.ts | 382 ++++++ .../src/contracts/propbook/registry.ts | 844 +++++++++++++ .../src/contracts/utils/index.ts | 234 ++++ packages/deepbook-predict/src/index.ts | 48 + .../deepbook-predict/src/queries/context.ts | 12 + .../deepbook-predict/src/queries/decode.ts | 36 + .../src/queries/indexerClient.ts | 227 ++++ .../src/queries/marketQueries.ts | 140 +++ .../src/queries/queries.test.ts | 158 +++ .../src/queries/vaultQueries.ts | 86 ++ .../src/transactions/account.ts | 106 ++ .../src/transactions/flush.ts | 127 ++ .../src/transactions/lp.test.ts | 98 ++ .../deepbook-predict/src/transactions/lp.ts | 240 ++++ .../src/transactions/predictAccount.ts | 52 + .../src/transactions/trade.ts | 271 +++++ .../src/transactions/transactions.test.ts | 174 +++ .../src/types/orderId.test.ts | 165 +++ .../deepbook-predict/src/types/orderId.ts | 160 +++ packages/deepbook-predict/src/utils/config.ts | 71 ++ .../deepbook-predict/src/utils/constants.ts | 43 + .../deepbook-predict/sui-codegen.config.ts | 33 + packages/deepbook-predict/tsconfig.json | 7 + packages/deepbook-predict/tsdown.config.ts | 12 + packages/deepbook-predict/vitest.config.mts | 18 + pnpm-lock.yaml | 514 +++++++- 74 files changed, 11693 insertions(+), 28 deletions(-) create mode 100644 packages/deepbook-predict/.prettierignore create mode 100644 packages/deepbook-predict/README.md create mode 100644 packages/deepbook-predict/package.json create mode 100644 packages/deepbook-predict/src/client.ts create mode 100644 packages/deepbook-predict/src/contracts/account/account.ts create mode 100644 packages/deepbook-predict/src/contracts/account/account_events.ts create mode 100644 packages/deepbook-predict/src/contracts/account/account_registry.ts create mode 100644 packages/deepbook-predict/src/contracts/account/deps/sui/bag.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/admin.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/builder_code.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/builder_code_events.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/config_events.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/deps/fixed_math/i64.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/deps/propbook/block_scholes_svi_feed.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/balance.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/coin.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/table.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/vec_set.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/ewma.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/ewma_config.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash_config.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/expiry_market.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/liquidation_book.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/lp_book.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/market_lifecycle_cap.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/market_manager.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/order.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/order_events.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/pause_cap.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/plp.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/pool_accounting.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/predict_account.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/pricing.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/pricing_config.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/protocol_config.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/registry.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/stake_config.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure_config.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/strike_payout_tree.ts create mode 100644 packages/deepbook-predict/src/contracts/deepbook_predict/vault_events.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/block_scholes_forward_feed.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/block_scholes_spot_feed.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/block_scholes_svi_feed.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/deps/fixed_math/i64.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/deps/sui/table.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/oracle_lane.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/pyth_feed.ts create mode 100644 packages/deepbook-predict/src/contracts/propbook/registry.ts create mode 100644 packages/deepbook-predict/src/contracts/utils/index.ts create mode 100644 packages/deepbook-predict/src/index.ts create mode 100644 packages/deepbook-predict/src/queries/context.ts create mode 100644 packages/deepbook-predict/src/queries/decode.ts create mode 100644 packages/deepbook-predict/src/queries/indexerClient.ts create mode 100644 packages/deepbook-predict/src/queries/marketQueries.ts create mode 100644 packages/deepbook-predict/src/queries/queries.test.ts create mode 100644 packages/deepbook-predict/src/queries/vaultQueries.ts create mode 100644 packages/deepbook-predict/src/transactions/account.ts create mode 100644 packages/deepbook-predict/src/transactions/flush.ts create mode 100644 packages/deepbook-predict/src/transactions/lp.test.ts create mode 100644 packages/deepbook-predict/src/transactions/lp.ts create mode 100644 packages/deepbook-predict/src/transactions/predictAccount.ts create mode 100644 packages/deepbook-predict/src/transactions/trade.ts create mode 100644 packages/deepbook-predict/src/transactions/transactions.test.ts create mode 100644 packages/deepbook-predict/src/types/orderId.test.ts create mode 100644 packages/deepbook-predict/src/types/orderId.ts create mode 100644 packages/deepbook-predict/src/utils/config.ts create mode 100644 packages/deepbook-predict/src/utils/constants.ts create mode 100644 packages/deepbook-predict/sui-codegen.config.ts create mode 100644 packages/deepbook-predict/tsconfig.json create mode 100644 packages/deepbook-predict/tsdown.config.ts create mode 100644 packages/deepbook-predict/vitest.config.mts diff --git a/packages/deepbook-predict/.prettierignore b/packages/deepbook-predict/.prettierignore new file mode 100644 index 000000000..b0894a4b7 --- /dev/null +++ b/packages/deepbook-predict/.prettierignore @@ -0,0 +1,9 @@ +dist/ +package-lock.json +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.next/ +.swc/ +out/ +CHANGELOG.md diff --git a/packages/deepbook-predict/README.md b/packages/deepbook-predict/README.md new file mode 100644 index 000000000..d1231fb31 --- /dev/null +++ b/packages/deepbook-predict/README.md @@ -0,0 +1,30 @@ +# `@mysten/deepbook-predict` + +TypeScript SDK for the DeepBook **Predict** protocol — on-chain European cash-settled range digitals +on Sui. + +> **Status: pre-launch, unstable.** Predict is not yet deployed to any network and its on-chain +> interface is still changing. There are no published package addresses; construct `PredictConfig` +> with explicit `packageIds` overrides. The API here will change without notice until the protocol +> ships to testnet. + +## Layout + +- `src/contracts/**` — generated Move bindings (`@mysten/codegen`), used as the BCS-schema source. + Regenerate with `pnpm codegen`. +- `src/transactions/**` — hand-written transaction builders (trader, LP, ...). +- `src/queries/**` — on-chain (`devInspect`) reads plus optional predict-server indexer helpers. +- `src/types/orderId.ts` — codec for the packed-`u256` order ID (mirrors `deepbook_predict::order`; + the Move module exposes no public accessors). +- `src/utils/{config,constants}.ts` — `PredictConfig` and protocol constants. + +## Codegen + +`pnpm codegen` runs `sui move summary` for each configured Move package (from the sibling +`deepbookv3` checkout) and regenerates `src/contracts/**`. Requires the Sui CLI (`>= 1.51.1`) and +the `deepbookv3` repo checked out alongside `ts-sdks`. + +## Scope (v1) + +Trader and LP flows; oracle **read-only**; slippage-guard-based trading (no off-chain quote +previewer). Keeper/admin/market-lifecycle and oracle publishing are deferred to later milestones. diff --git a/packages/deepbook-predict/package.json b/packages/deepbook-predict/package.json new file mode 100644 index 000000000..c928d34b9 --- /dev/null +++ b/packages/deepbook-predict/package.json @@ -0,0 +1,56 @@ +{ + "name": "@mysten/deepbook-predict", + "author": "Mysten Labs ", + "description": "Sui DeepBook Predict SDK", + "version": "0.0.0", + "license": "Apache-2.0", + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "default": "./dist/index.mjs" + } + }, + "files": [ + "CHANGELOG.md", + "dist", + "src" + ], + "engines": { + "node": ">=22" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/MystenLabs/ts-sdks.git" + }, + "bugs": { + "url": "https://github.com/MystenLabs/ts-sdks/issues/new" + }, + "scripts": { + "clean": "rm -rf tsconfig.tsbuildinfo ./dist", + "build": "rm -rf dist && tsc --noEmit && tsdown", + "codegen": "pnpm sui-ts-codegen generate && pnpm lint:fix", + "prettier:check": "prettier -c --ignore-unknown .", + "prettier:fix": "prettier -w --ignore-unknown .", + "oxlint:check": "oxlint .", + "oxlint:fix": "oxlint --fix", + "test": "vitest", + "lint": "pnpm run oxlint:check && pnpm run prettier:check", + "lint:fix": "pnpm run oxlint:fix && pnpm run prettier:fix" + }, + "dependencies": { + "@mysten/bcs": "workspace:^" + }, + "devDependencies": { + "@mysten/codegen": "workspace:^", + "@types/node": "^25.0.8", + "typescript": "^5.9.3", + "vitest": "^4.0.17" + }, + "peerDependencies": { + "@mysten/sui": "workspace:^" + } +} diff --git a/packages/deepbook-predict/src/client.ts b/packages/deepbook-predict/src/client.ts new file mode 100644 index 000000000..6162e7e60 --- /dev/null +++ b/packages/deepbook-predict/src/client.ts @@ -0,0 +1,95 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import type { ClientWithCoreApi, SuiClientRegistration, SuiClientTypes } from '@mysten/sui/client'; +import { normalizeSuiAddress } from '@mysten/sui/utils'; + +import { IndexerClient } from './queries/indexerClient.js'; +import { MarketQueries } from './queries/marketQueries.js'; +import { VaultQueries } from './queries/vaultQueries.js'; +import { AccountContract } from './transactions/account.js'; +import { FlushContract } from './transactions/flush.js'; +import { LpContract } from './transactions/lp.js'; +import { PredictAccountContract } from './transactions/predictAccount.js'; +import { TradeContract } from './transactions/trade.js'; +import { PredictConfig } from './utils/config.js'; +import type { PredictIds, PredictNetwork } from './utils/config.js'; + +/** A Sui client with the core API (`client.core.simulateTransaction`) the queries use. */ +export interface PredictCompatibleClient extends ClientWithCoreApi {} + +export interface PredictOptions { + /** Default sender for built transactions. */ + address: string; + /** On-chain package + shared-object ids. Required until Predict is published. */ + ids: PredictIds; + /** Optional `predict-server` base URL enabling the indexer read helpers. */ + indexerUrl?: string; + name?: Name; +} + +export interface PredictClientOptions extends PredictOptions { + client: PredictCompatibleClient; + network: SuiClientTypes.Network; +} + +/** + * Facade over the Predict transaction builders + on-chain/indexer queries. + * + * Construct directly, or register onto a Sui client with + * `suiClient.$extend(predict({ address, ids }))` and use `suiClient.predict`. + */ +export class PredictClient { + readonly config: PredictConfig; + + // Transaction builders + readonly account: AccountContract; + readonly predictAccount: PredictAccountContract; + readonly trade: TradeContract; + readonly lp: LpContract; + readonly flush: FlushContract; + + // On-chain read helpers + readonly market: MarketQueries; + readonly vault: VaultQueries; + + /** Indexer read helpers; present only when `indexerUrl` was configured. */ + readonly indexer?: IndexerClient; + + constructor({ client, network, address, ids, indexerUrl }: PredictClientOptions) { + const normalizedAddress = normalizeSuiAddress(address); + this.config = new PredictConfig({ + network: network as PredictNetwork, + address: normalizedAddress, + indexerUrl, + ids, + }); + + this.account = new AccountContract(this.config); + this.predictAccount = new PredictAccountContract(this.config); + this.trade = new TradeContract(this.config); + this.lp = new LpContract(this.config); + this.flush = new FlushContract(this.config); + + const ctx = { client, config: this.config, address: normalizedAddress }; + this.market = new MarketQueries(ctx); + this.vault = new VaultQueries(ctx); + + if (indexerUrl) { + this.indexer = new IndexerClient({ baseUrl: indexerUrl }); + } + } +} + +/** `$extend` registration: `suiClient.$extend(predict({ address, ids }))`. */ +export function predict({ + name = 'predict' as Name, + ...options +}: PredictOptions): SuiClientRegistration { + return { + name, + register: (client) => { + return new PredictClient({ client, network: client.network, ...options }); + }, + }; +} diff --git a/packages/deepbook-predict/src/contracts/account/account.ts b/packages/deepbook-predict/src/contracts/account/account.ts new file mode 100644 index 000000000..4a7cc6173 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/account/account.ts @@ -0,0 +1,584 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * A pure, reusable on-chain account: a shared wrapper owns the account data and + * controls who can borrow it mutably. + * + * Owner, object-owner, and app flows consume an `Auth` hot potato to load + * `&mut Account` from the wrapper. Once a caller has a mutable account reference, + * value movement needs no extra proof: the borrow itself is the authority + * boundary. Coin reads include funds delivered to this account's accumulator + * address, and coin writes first settle those funds into the account. + * + * Apps also store opaque per-account state through the app-data lane (`attach` / + * `borrow_data` / `detach`): a dynamic field namespaced by the app's witness type, + * so apps cannot collide. Mutations require `Permit`; reads are open. + */ + +import { + MoveStruct, + MoveTuple, + normalizeMoveArguments, + type RawTransactionArgument, +} from '../utils/index.js'; +import { bcs, type BcsType } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as bag from './deps/sui/bag.js'; +import * as bag_1 from './deps/sui/bag.js'; +const $moduleName = '@local-pkg/account::account'; +export const Account = new MoveStruct({ + name: `${$moduleName}::Account`, + fields: { + account_id: bcs.Address, + /** EOA address or object-ID-as-address that owns this account. */ + owner: bcs.Address, + /** + * The wrapper object's address: the accumulator/funds-receive anchor. Funds are + * delivered here and settled out via `&mut AccountWrapper.id` — a real shared + * object the runtime can authenticate, unlike the nested `account_id` UID, which + * can never back an address-balance withdrawal. + */ + receive_address: bcs.Address, + balances: bag.Bag, + settlements: bag_1.Bag, + }, +}); +export const AccountWrapper = new MoveStruct({ + name: `${$moduleName}::AccountWrapper`, + fields: { + id: bcs.Address, + account: Account, + }, +}); +export const DataKey = new MoveTuple({ + name: `${$moduleName}::DataKey`, + fields: [bcs.bool()], +}); +export const CoinKey = new MoveStruct({ + name: `${$moduleName}::CoinKey`, + fields: { + dummy_field: bcs.bool(), + }, +}); +export const Auth = new MoveStruct({ + name: `${$moduleName}::Auth`, + fields: { + kind: bcs.u8(), + owner: bcs.Address, + }, +}); +export interface ShareArguments { + self: RawTransactionArgument; +} +export interface ShareOptions { + package?: string; + arguments: ShareArguments | [self: RawTransactionArgument]; +} +/** Share a newly created account object. */ +export function share(options: ShareOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'share', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface IdArguments { + self: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [self: RawTransactionArgument]; +} +/** Returns the wrapper object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface GenerateAuthOptions { + package?: string; + arguments?: []; +} +/** Generate owner authority from the transaction sender. */ +export function generateAuth(options: GenerateAuthOptions = {}) { + const packageAddress = options.package ?? '@local-pkg/account'; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'generate_auth', + }); +} +export interface GenerateAuthAsObjectArguments { + uid: RawTransactionArgument; +} +export interface GenerateAuthAsObjectOptions { + package?: string; + arguments: GenerateAuthAsObjectArguments | [uid: RawTransactionArgument]; +} +/** Generate owner authority from an owning object's UID. */ +export function generateAuthAsObject(options: GenerateAuthAsObjectOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = ['0x2::object::ID'] satisfies (string | null)[]; + const parameterNames = ['uid']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'generate_auth_as_object', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface LoadAccountArguments { + self: RawTransactionArgument; +} +export interface LoadAccountOptions { + package?: string; + arguments: LoadAccountArguments | [self: RawTransactionArgument]; +} +/** Borrow the wrapped account for read-only use. */ +export function loadAccount(options: LoadAccountOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'load_account', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface LoadAccountMutArguments { + self: RawTransactionArgument; + auth: RawTransactionArgument; +} +export interface LoadAccountMutOptions { + package?: string; + arguments: + | LoadAccountMutArguments + | [self: RawTransactionArgument, auth: RawTransactionArgument]; +} +/** Borrow the wrapped account mutably by consuming an `Auth` hot potato. */ +export function loadAccountMut(options: LoadAccountMutOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['self', 'auth']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'load_account_mut', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BalanceArguments { + self: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface BalanceOptions { + package?: string; + arguments: + | BalanceArguments + | [self: RawTransactionArgument, root: RawTransactionArgument]; + typeArguments: [string]; +} +/** + * Returns the total balance of `T` available to the account, including funds + * delivered through the ambient accumulator but not yet settled into the account. + */ +export function balance(options: BalanceOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['self', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'balance', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface OwnerArguments { + self: RawTransactionArgument; +} +export interface OwnerOptions { + package?: string; + arguments: OwnerArguments | [self: RawTransactionArgument]; +} +/** + * Returns the account owner address. This may be an EOA address or an + * object-ID-as-address. + */ +export function owner(options: OwnerOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'owner', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface AccountIdArguments { + self: RawTransactionArgument; +} +export interface AccountIdOptions { + package?: string; + arguments: AccountIdArguments | [self: RawTransactionArgument]; +} +/** Returns the canonical account ID. */ +export function accountId(options: AccountIdOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'account_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ReceiveAddressArguments { + self: RawTransactionArgument; +} +export interface ReceiveAddressOptions { + package?: string; + arguments: ReceiveAddressArguments | [self: RawTransactionArgument]; +} +/** Returns the accumulator receive address for this account (the wrapper address). */ +export function receiveAddress(options: ReceiveAddressOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'receive_address', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SettleArguments { + wrapper: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface SettleOptions { + package?: string; + arguments: + | SettleArguments + | [wrapper: RawTransactionArgument, root: RawTransactionArgument]; + typeArguments: [string]; +} +/** + * Fold any accumulator-delivered funds for `T` (sent to this account's receive + * address) into stored balance. Withdrawing the address balance uses + * `&mut wrapper.id` — a real shared object the runtime authenticates as a + * transaction input. Each public flow that touches `T` settles at its boundary, + * where the wrapper is in scope, so the deep `&mut Account` custody ops below stay + * pure stored-balance. + * + * Permissionless: it only consolidates the account's own funds and moves nothing + * out, so it needs no `Auth`; pulling funds out still requires + * `load_account_mut(auth)`. + */ +export function settle(options: SettleOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['wrapper', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'settle', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface DepositArguments { + self: RawTransactionArgument; + coin: RawTransactionArgument; +} +export interface DepositOptions { + package?: string; + arguments: + | DepositArguments + | [self: RawTransactionArgument, coin: RawTransactionArgument]; + typeArguments: [string]; +} +/** + * Deposit `coin` into the wrapped account's stored `T` balance. Pure + * stored-balance: callers settle accumulator funds at the flow boundary via + * `settle` (the deep `&mut Account` here cannot reach the wrapper id needed to + * authenticate a settle). + */ +export function deposit(options: DepositOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['self', 'coin']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'deposit', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface WithdrawArguments { + self: RawTransactionArgument; + amount: RawTransactionArgument; +} +export interface WithdrawOptions { + package?: string; + arguments: + | WithdrawArguments + | [self: RawTransactionArgument, amount: RawTransactionArgument]; + typeArguments: [string]; +} +/** + * Withdraw `amount` of `T` from stored balance. Pure stored-balance (see + * `deposit`): callers settle accumulator funds at the flow boundary via `settle` + * first. + */ +export function withdraw(options: WithdrawOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['self', 'amount']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'withdraw', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface DepositFundsArguments { + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + coin: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface DepositFundsOptions { + package?: string; + arguments: + | DepositFundsArguments + | [ + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + coin: RawTransactionArgument, + root: RawTransactionArgument, + ]; + typeArguments: [string]; +} +/** + * Deposit `coin` into the wrapped account's stored `T` balance from a transaction. + * `deposit` borrows `&mut Account`, which a PTB cannot carry across commands out + * of `load_account_mut`, so this folds settle → authorize → load → deposit into + * one entrypoint (the same shape predict's `mint`/`redeem` use for + * account-authorized flows). + */ +export function depositFunds(options: DepositFundsOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null, null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['wrapper', 'auth', 'coin', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'deposit_funds', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface WithdrawFundsArguments { + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + amount: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface WithdrawFundsOptions { + package?: string; + arguments: + | WithdrawFundsArguments + | [ + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + amount: RawTransactionArgument, + root: RawTransactionArgument, + ]; + typeArguments: [string]; +} +/** + * PTB-callable withdraw: folds settle → authorize → load → withdraw into one + * entrypoint (see `deposit_funds`). + */ +export function withdrawFunds(options: WithdrawFundsOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null, 'u64', null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['wrapper', 'auth', 'amount', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'withdraw_funds', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface AttachArguments> { + self: RawTransactionArgument; + Permit: RawTransactionArgument; + data: RawTransactionArgument; +} +export interface AttachOptions> { + package?: string; + arguments: + | AttachArguments + | [ + self: RawTransactionArgument, + Permit: RawTransactionArgument, + data: RawTransactionArgument, + ]; + typeArguments: [string, string]; +} +/** + * Attach an app's `Data` under its witness namespace. Requires `Permit`. + * Aborts if `App` already has data attached. + */ +export function attach>(options: AttachOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null, `${options.typeArguments[1]}`] satisfies (string | null)[]; + const parameterNames = ['self', 'Permit', 'data']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'attach', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface HasDataArguments { + self: RawTransactionArgument; +} +export interface HasDataOptions { + package?: string; + arguments: HasDataArguments | [self: RawTransactionArgument]; + typeArguments: [string]; +} +/** Whether `App` has data attached to this account. */ +export function hasData(options: HasDataOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'has_data', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface BorrowDataArguments { + self: RawTransactionArgument; +} +export interface BorrowDataOptions { + package?: string; + arguments: BorrowDataArguments | [self: RawTransactionArgument]; + typeArguments: [string, string]; +} +/** + * Borrow an app's attached `Data`. Open (no witness): the slot is namespaced by + * `App` and on-chain state is public, so composing apps can read it. Aborts if + * nothing is attached. + */ +export function borrowData(options: BorrowDataOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['self']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'borrow_data', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface BorrowDataMutArguments { + self: RawTransactionArgument; + Permit: RawTransactionArgument; +} +export interface BorrowDataMutOptions { + package?: string; + arguments: + | BorrowDataMutArguments + | [self: RawTransactionArgument, Permit: RawTransactionArgument]; + typeArguments: [string, string]; +} +/** + * Mutably borrow an app's attached `Data`. Requires `Permit`. Aborts if + * nothing is attached. + */ +export function borrowDataMut(options: BorrowDataMutOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['self', 'Permit']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'borrow_data_mut', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface DetachArguments { + self: RawTransactionArgument; + Permit: RawTransactionArgument; +} +export interface DetachOptions { + package?: string; + arguments: + | DetachArguments + | [self: RawTransactionArgument, Permit: RawTransactionArgument]; + typeArguments: [string, string]; +} +/** + * Detach and return an app's `Data`. Requires `Permit`. Aborts if nothing is + * attached. + */ +export function detach(options: DetachOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['self', 'Permit']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account', + function: 'detach', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} diff --git a/packages/deepbook-predict/src/contracts/account/account_events.ts b/packages/deepbook-predict/src/contracts/account/account_events.ts new file mode 100644 index 000000000..5aed0deb4 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/account/account_events.ts @@ -0,0 +1,63 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Account-domain events: canonical-account lifecycle, app-whitelist governance, + * and per-coin custody movement. Emitted by the modules that own each transition + * (`account_registry` for lifecycle, `account` for custody). This is the package's + * only event surface; indexing lives in follow-up account indexer work. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/account::account_events'; +export const AccountCreated = new MoveStruct({ + name: `${$moduleName}::AccountCreated`, + fields: { + account_id: bcs.Address, + wrapper_id: bcs.Address, + owner: bcs.Address, + self_owned: bcs.bool(), + }, +}); +export const AppAuthorized = new MoveStruct({ + name: `${$moduleName}::AppAuthorized`, + fields: { + /** Fully-qualified `App` witness type name. */ + app: bcs.string(), + }, +}); +export const AppDeauthorized = new MoveStruct({ + name: `${$moduleName}::AppDeauthorized`, + fields: { + app: bcs.string(), + }, +}); +export const Deposited = new MoveStruct({ + name: `${$moduleName}::Deposited`, + fields: { + account_id: bcs.Address, + coin_type: bcs.string(), + amount: bcs.u64(), + new_balance: bcs.u64(), + }, +}); +export const Withdrawn = new MoveStruct({ + name: `${$moduleName}::Withdrawn`, + fields: { + account_id: bcs.Address, + coin_type: bcs.string(), + amount: bcs.u64(), + new_balance: bcs.u64(), + }, +}); +export const FundsSettled = new MoveStruct({ + name: `${$moduleName}::FundsSettled`, + fields: { + account_id: bcs.Address, + coin_type: bcs.string(), + amount: bcs.u64(), + new_balance: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/account/account_registry.ts b/packages/deepbook-predict/src/contracts/account/account_registry.ts new file mode 100644 index 000000000..5a96c8f98 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/account/account_registry.ts @@ -0,0 +1,311 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Shared registry for canonical account creation. + * + * The registry owns the derivation root and controls the ecosystem app whitelist. + * `account::account` owns deterministic wrapper derivation, account construction, + * custody, settlement, and app-data invariants. + */ + +import { + MoveStruct, + MoveTuple, + normalizeMoveArguments, + type RawTransactionArgument, +} from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +const $moduleName = '@local-pkg/account::account_registry'; +export const AccountAdminCap = new MoveStruct({ + name: `${$moduleName}::AccountAdminCap`, + fields: { + id: bcs.Address, + }, +}); +export const AccountRegistry = new MoveStruct({ + name: `${$moduleName}::AccountRegistry`, + fields: { + id: bcs.Address, + }, +}); +export const AccountKey = new MoveTuple({ + name: `${$moduleName}::AccountKey`, + fields: [bcs.Address], +}); +export const AccountWrapperKey = new MoveTuple({ + name: `${$moduleName}::AccountWrapperKey`, + fields: [bcs.Address], +}); +export const AppKey = new MoveTuple({ + name: `${$moduleName}::AppKey`, + fields: [bcs.bool()], +}); +export interface DerivedAddressArguments { + registry: RawTransactionArgument; + owner: RawTransactionArgument; +} +export interface DerivedAddressOptions { + package?: string; + arguments: + | DerivedAddressArguments + | [registry: RawTransactionArgument, owner: RawTransactionArgument]; +} +/** + * Return the deterministic canonical account address for `owner` under this + * registry. + */ +export function derivedAddress(options: DerivedAddressOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, 'address'] satisfies (string | null)[]; + const parameterNames = ['registry', 'owner']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'derived_address', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface DerivedWrapperAddressArguments { + registry: RawTransactionArgument; + owner: RawTransactionArgument; +} +export interface DerivedWrapperAddressOptions { + package?: string; + arguments: + | DerivedWrapperAddressArguments + | [registry: RawTransactionArgument, owner: RawTransactionArgument]; +} +/** + * Return the deterministic account wrapper address for `owner` under this + * registry. + */ +export function derivedWrapperAddress(options: DerivedWrapperAddressOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, 'address'] satisfies (string | null)[]; + const parameterNames = ['registry', 'owner']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'derived_wrapper_address', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface DerivedExistsArguments { + registry: RawTransactionArgument; + owner: RawTransactionArgument; +} +export interface DerivedExistsOptions { + package?: string; + arguments: + | DerivedExistsArguments + | [registry: RawTransactionArgument, owner: RawTransactionArgument]; +} +/** Return whether the canonical derived account has already been claimed. */ +export function derivedExists(options: DerivedExistsOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, 'address'] satisfies (string | null)[]; + const parameterNames = ['registry', 'owner']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'derived_exists', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface DerivedWrapperExistsArguments { + registry: RawTransactionArgument; + owner: RawTransactionArgument; +} +export interface DerivedWrapperExistsOptions { + package?: string; + arguments: + | DerivedWrapperExistsArguments + | [registry: RawTransactionArgument, owner: RawTransactionArgument]; +} +/** Return whether the derived account wrapper has already been claimed. */ +export function derivedWrapperExists(options: DerivedWrapperExistsOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, 'address'] satisfies (string | null)[]; + const parameterNames = ['registry', 'owner']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'derived_wrapper_exists', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NewArguments { + registry: RawTransactionArgument; +} +export interface NewOptions { + package?: string; + arguments: NewArguments | [registry: RawTransactionArgument]; +} +/** Create the sender's canonical derived account wrapper. */ +export function _new(options: NewOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['registry']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'new', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NewSelfOwnedArguments { + registry: RawTransactionArgument; + ownerUid: RawTransactionArgument; +} +export interface NewSelfOwnedOptions { + package?: string; + arguments: + | NewSelfOwnedArguments + | [registry: RawTransactionArgument, ownerUid: RawTransactionArgument]; +} +/** + * Create the canonical derived account wrapper owned by `owner_uid`'s object + * address. + */ +export function newSelfOwned(options: NewSelfOwnedOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, '0x2::object::ID'] satisfies (string | null)[]; + const parameterNames = ['registry', 'ownerUid']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'new_self_owned', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface IsAppAuthorizedArguments { + registry: RawTransactionArgument; +} +export interface IsAppAuthorizedOptions { + package?: string; + arguments: IsAppAuthorizedArguments | [registry: RawTransactionArgument]; + typeArguments: [string]; +} +/** Return whether `App` is authorized for app-driven account access. */ +export function isAppAuthorized(options: IsAppAuthorizedOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['registry']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'is_app_authorized', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface AuthorizeAppArguments { + registry: RawTransactionArgument; + Cap: RawTransactionArgument; +} +export interface AuthorizeAppOptions { + package?: string; + arguments: + | AuthorizeAppArguments + | [registry: RawTransactionArgument, Cap: RawTransactionArgument]; + typeArguments: [string]; +} +/** Authorize `App` to generate app auth through this registry. */ +export function authorizeApp(options: AuthorizeAppOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['registry', 'Cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'authorize_app', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface DeauthorizeAppArguments { + registry: RawTransactionArgument; + Cap: RawTransactionArgument; +} +export interface DeauthorizeAppOptions { + package?: string; + arguments: + | DeauthorizeAppArguments + | [registry: RawTransactionArgument, Cap: RawTransactionArgument]; + typeArguments: [string]; +} +/** Remove `App` from the app account-loading whitelist. */ +export function deauthorizeApp(options: DeauthorizeAppOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['registry', 'Cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'deauthorize_app', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface AssertAppIsAuthorizedArguments { + registry: RawTransactionArgument; +} +export interface AssertAppIsAuthorizedOptions { + package?: string; + arguments: AssertAppIsAuthorizedArguments | [registry: RawTransactionArgument]; + typeArguments: [string]; +} +/** Assert that `App` is authorized for app-driven account access. */ +export function assertAppIsAuthorized(options: AssertAppIsAuthorizedOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['registry']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'assert_app_is_authorized', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface GenerateAuthAsAppArguments { + registry: RawTransactionArgument; + Permit: RawTransactionArgument; +} +export interface GenerateAuthAsAppOptions { + package?: string; + arguments: + | GenerateAuthAsAppArguments + | [registry: RawTransactionArgument, Permit: RawTransactionArgument]; + typeArguments: [string]; +} +/** + * Generate app authority after checking the registry whitelist. The `Permit` + * proves the caller is the module defining `App`. + */ +export function generateAuthAsApp(options: GenerateAuthAsAppOptions) { + const packageAddress = options.package ?? '@local-pkg/account'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['registry', 'Permit']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'account_registry', + function: 'generate_auth_as_app', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} diff --git a/packages/deepbook-predict/src/contracts/account/deps/sui/bag.ts b/packages/deepbook-predict/src/contracts/account/deps/sui/bag.ts new file mode 100644 index 000000000..f8966dc9e --- /dev/null +++ b/packages/deepbook-predict/src/contracts/account/deps/sui/bag.ts @@ -0,0 +1,41 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * A bag is a heterogeneous map-like collection. The collection is similar to + * `sui::table` in that its keys and values are not stored within the `Bag` value, + * but instead are stored using Sui's object system. The `Bag` struct acts only as + * a handle into the object system to retrieve those keys and values. Note that + * this means that `Bag` values with exactly the same key-value mapping will not be + * equal, with `==`, at runtime. For example + * + * ``` + * let bag1 = bag::new(); + * let bag2 = bag::new(); + * bag::add(&mut bag1, 0, false); + * bag::add(&mut bag1, 1, true); + * bag::add(&mut bag2, 0, false); + * bag::add(&mut bag2, 1, true); + * // bag1 does not equal bag2, despite having the same entries + * assert!(&bag1 != &bag2); + * ``` + * + * At it's core, `sui::bag` is a wrapper around `UID` that allows for access to + * `sui::dynamic_field` while preventing accidentally stranding field values. A + * `UID` can be deleted, even if it has dynamic fields associated with it, but a + * bag, on the other hand, must be empty to be destroyed. + */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '0x2::bag'; +export const Bag = new MoveStruct({ + name: `${$moduleName}::Bag`, + fields: { + /** the ID of this bag */ + id: bcs.Address, + /** the number of key-value pairs in the bag */ + size: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/admin.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/admin.ts new file mode 100644 index 000000000..6f8f99eb9 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/admin.ts @@ -0,0 +1,42 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Administrative authority for Predict governance operations. + * + * The package initializer creates one `AdminCap` and transfers it to the deployer. + * Modules that own admin-controlled state accept this capability directly instead + * of routing unrelated mutations through the registry. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +const $moduleName = '@local-pkg/deepbook_predict::admin'; +export const AdminCap = new MoveStruct({ + name: `${$moduleName}::AdminCap`, + fields: { + id: bcs.Address, + }, +}); +export interface IdArguments { + cap: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [cap: RawTransactionArgument]; +} +/** Return the admin cap object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'admin', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/builder_code.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/builder_code.ts new file mode 100644 index 000000000..68afda00e --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/builder_code.ts @@ -0,0 +1,139 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Builder code identity and reward claiming for Predict. + * + * Builder codes are deterministic shared objects derived from the Predict + * registry. Trade flows send add-on builder fees to the code object's address + * balance, and the code owner can later claim those accumulated DUSDC funds. + */ + +import { + MoveTuple, + MoveStruct, + normalizeMoveArguments, + type RawTransactionArgument, +} from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +const $moduleName = '@local-pkg/deepbook_predict::builder_code'; +export const BuilderCodeKey = new MoveTuple({ + name: `${$moduleName}::BuilderCodeKey`, + fields: [bcs.Address, bcs.u64()], +}); +export const BuilderCode = new MoveStruct({ + name: `${$moduleName}::BuilderCode`, + fields: { + id: bcs.Address, + owner: bcs.Address, + index: bcs.u64(), + }, +}); +export interface IdArguments { + code: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [code: RawTransactionArgument]; +} +/** Return the builder code object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['code']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'builder_code', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface OwnerArguments { + code: RawTransactionArgument; +} +export interface OwnerOptions { + package?: string; + arguments: OwnerArguments | [code: RawTransactionArgument]; +} +/** Return the permanent owner of this builder code. */ +export function owner(options: OwnerOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['code']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'builder_code', + function: 'owner', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface IndexArguments { + code: RawTransactionArgument; +} +export interface IndexOptions { + package?: string; + arguments: IndexArguments | [code: RawTransactionArgument]; +} +/** Return this owner's builder-code index. */ +export function index(options: IndexOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['code']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'builder_code', + function: 'index', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ClaimableBuilderFeesArguments { + root: RawTransactionArgument; + code: RawTransactionArgument; +} +export interface ClaimableBuilderFeesOptions { + package?: string; + arguments: + | ClaimableBuilderFeesArguments + | [root: RawTransactionArgument, code: RawTransactionArgument]; +} +/** Return the DUSDC builder fees currently visible for this code. */ +export function claimableBuilderFees(options: ClaimableBuilderFeesOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['root', 'code']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'builder_code', + function: 'claimable_builder_fees', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ClaimAllBuilderFeesArguments { + code: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface ClaimAllBuilderFeesOptions { + package?: string; + arguments: + | ClaimAllBuilderFeesArguments + | [code: RawTransactionArgument, root: RawTransactionArgument]; +} +/** Claim all settled DUSDC builder fees accumulated for this code. */ +export function claimAllBuilderFees(options: ClaimAllBuilderFeesOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['code', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'builder_code', + function: 'claim_all_builder_fees', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/builder_code_events.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/builder_code_events.ts new file mode 100644 index 000000000..41ddd61cf --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/builder_code_events.ts @@ -0,0 +1,33 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** Builder-code lifecycle and attribution events for Predict. */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::builder_code_events'; +export const BuilderCodeCreated = new MoveStruct({ + name: `${$moduleName}::BuilderCodeCreated`, + fields: { + builder_code_id: bcs.Address, + owner: bcs.Address, + builder_code_index: bcs.u64(), + }, +}); +export const BuilderCodeSet = new MoveStruct({ + name: `${$moduleName}::BuilderCodeSet`, + fields: { + account_id: bcs.Address, + owner: bcs.Address, + builder_code_id: bcs.option(bcs.Address), + }, +}); +export const BuilderFeesClaimed = new MoveStruct({ + name: `${$moduleName}::BuilderFeesClaimed`, + fields: { + builder_code_id: bcs.Address, + owner: bcs.Address, + amount: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/config_events.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/config_events.ts new file mode 100644 index 000000000..63e8f811e --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/config_events.ts @@ -0,0 +1,75 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** Admin and configuration events for Predict. */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::config_events'; +export const TradingPausedUpdated = new MoveStruct({ + name: `${$moduleName}::TradingPausedUpdated`, + fields: { + protocol_config_id: bcs.Address, + paused: bcs.bool(), + }, +}); +export const MarketCreated = new MoveStruct({ + name: `${$moduleName}::MarketCreated`, + fields: { + expiry_market_id: bcs.Address, + pool_vault_id: bcs.Address, + /** Propbook underlying this market resolves current oracle bindings through. */ + propbook_underlying_id: bcs.u32(), + expiry: bcs.u64(), + /** + * Raw-price-per-tick factor; indexers/SDKs derive raw strikes as + * `tick * tick_size`. + */ + tick_size: bcs.u64(), + /** Coarser raw-price step that new finite mint boundaries must align to. */ + admission_tick_size: bcs.u64(), + /** DUSDC pool allocation cap snapshotted for this expiry. */ + max_expiry_allocation: bcs.u64(), + /** Minimum DUSDC cash target snapshotted for this expiry. */ + initial_expiry_cash: bcs.u64(), + liquidation_ltv: bcs.u64(), + max_admission_leverage: bcs.u64(), + backing_buffer_lambda: bcs.u64(), + base_fee: bcs.u64(), + min_fee: bcs.u64(), + min_entry_probability: bcs.u64(), + max_entry_probability: bcs.u64(), + expiry_fee_window_ms: bcs.u64(), + expiry_fee_max_multiplier: bcs.u64(), + trading_loss_rebate_rate: bcs.u64(), + }, +}); +export const ExpiryMarketMintPausedUpdated = new MoveStruct({ + name: `${$moduleName}::ExpiryMarketMintPausedUpdated`, + fields: { + expiry_market_id: bcs.Address, + paused: bcs.bool(), + }, +}); +export const ReferenceTickSet = new MoveStruct({ + name: `${$moduleName}::ReferenceTickSet`, + fields: { + expiry_market_id: bcs.Address, + propbook_underlying_id: bcs.u32(), + source_timestamp_ms: bcs.u64(), + spot: bcs.u64(), + tick: bcs.u64(), + }, +}); +export const MarketSettled = new MoveStruct({ + name: `${$moduleName}::MarketSettled`, + fields: { + expiry_market_id: bcs.Address, + propbook_underlying_id: bcs.u32(), + expiry: bcs.u64(), + settlement_price: bcs.u64(), + /** On-chain landing time of the settlement, `clock.timestamp_ms()`. */ + settled_at_ms: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/deps/fixed_math/i64.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/fixed_math/i64.ts new file mode 100644 index 000000000..ed1c669a4 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/fixed_math/i64.ts @@ -0,0 +1,16 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** Signed u64 magnitude with normalized zero. */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = 'fixed_math::i64'; +export const I64 = new MoveStruct({ + name: `${$moduleName}::I64`, + fields: { + magnitude: bcs.u64(), + is_negative: bcs.bool(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/deps/propbook/block_scholes_svi_feed.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/propbook/block_scholes_svi_feed.ts new file mode 100644 index 000000000..c839ef05d --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/propbook/block_scholes_svi_feed.ts @@ -0,0 +1,27 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Block Scholes SVI oracle: one shared object per source id, storing per-expiry + * volatility-surface streams keyed by expiry timestamp. + * + * Propbook does not validate Predict's pricing-safe SVI envelope; consumers own + * any bounds or no-arbitrage policy needed by their pricing math. + */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as i64 from '../fixed_math/i64.js'; +import * as i64_1 from '../fixed_math/i64.js'; +const $moduleName = 'propbook::block_scholes_svi_feed'; +export const SVIParams = new MoveStruct({ + name: `${$moduleName}::SVIParams`, + fields: { + a: bcs.u64(), + b: bcs.u64(), + rho: i64.I64, + m: i64_1.I64, + sigma: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/balance.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/balance.ts new file mode 100644 index 000000000..38bdf984c --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/balance.ts @@ -0,0 +1,25 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * A storable handler for Balances in general. Is used in the `Coin` module to + * allow balance operations and can be used to implement custom coins with `Supply` + * and `Balance`s. + */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '0x2::balance'; +export const Balance = new MoveStruct({ + name: `${$moduleName}::Balance`, + fields: { + value: bcs.u64(), + }, +}); +export const Supply = new MoveStruct({ + name: `${$moduleName}::Supply`, + fields: { + value: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/coin.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/coin.ts new file mode 100644 index 000000000..529c03b36 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/coin.ts @@ -0,0 +1,20 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Defines the `Coin` type - platform wide representation of fungible tokens and + * coins. `Coin` can be described as a secure wrapper around `Balance` type. + */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as balance from './balance.js'; +const $moduleName = '0x2::coin'; +export const TreasuryCap = new MoveStruct({ + name: `${$moduleName}::TreasuryCap`, + fields: { + id: bcs.Address, + total_supply: balance.Supply, + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/table.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/table.ts new file mode 100644 index 000000000..41e18b1d1 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/table.ts @@ -0,0 +1,36 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * A table is a map-like collection. But unlike a traditional collection, it's keys + * and values are not stored within the `Table` value, but instead are stored using + * Sui's object system. The `Table` struct acts only as a handle into the object + * system to retrieve those keys and values. Note that this means that `Table` + * values with exactly the same key-value mapping will not be equal, with `==`, at + * runtime. For example + * + * ``` + * let table1 = table::new(); + * let table2 = table::new(); + * table::add(&mut table1, 0, false); + * table::add(&mut table1, 1, true); + * table::add(&mut table2, 0, false); + * table::add(&mut table2, 1, true); + * // table1 does not equal table2, despite having the same entries + * assert!(&table1 != &table2); + * ``` + */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '0x2::table'; +export const Table = new MoveStruct({ + name: `${$moduleName}::Table`, + fields: { + /** the ID of this table */ + id: bcs.Address, + /** the number of key-value pairs in the table */ + size: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/vec_set.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/vec_set.ts new file mode 100644 index 000000000..f73afa257 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/deps/sui/vec_set.ts @@ -0,0 +1,22 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ +import { type BcsType, bcs } from '@mysten/sui/bcs'; +import { MoveStruct } from '../../../utils/index.js'; +const $moduleName = '0x2::vec_set'; +/** + * A set data structure backed by a vector. The set is guaranteed not to contain + * duplicate keys. All operations are O(N) in the size of the set + * + * - the intention of this data structure is only to provide the convenience of + * programming against a set API. Sets that need sorted iteration rather than + * insertion order iteration should be handwritten. + */ +export function VecSet>(...typeParameters: [K]) { + return new MoveStruct({ + name: `${$moduleName}::VecSet<${typeParameters[0].name as K['name']}>`, + fields: { + contents: bcs.vector(typeParameters[0]), + }, + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/ewma.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/ewma.ts new file mode 100644 index 000000000..d43e7c270 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/ewma.ts @@ -0,0 +1,27 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Per-market exponentially-weighted gas-price statistics used to surcharge trades + * placed during abnormal network congestion, mirroring DeepBook core's gas-price + * EWMA penalty. + * + * This module owns only the evolving `(mean, variance)` estimate and the gas-price + * observation and penalty math. The tunable knobs (`alpha`, `z_score_threshold`, + * `penalty_rate`, `enabled`) live in `EwmaConfig`; `ExpiryMarket` owns the stored + * state and decides when to fold observations in. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::ewma'; +export const EwmaState = new MoveStruct({ + name: `${$moduleName}::EwmaState`, + fields: { + mean: bcs.u64(), + variance: bcs.u64(), + /** On-chain time of the last fold; guards against more than one update per ms. */ + last_updated_timestamp_ms: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/ewma_config.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/ewma_config.ts new file mode 100644 index 000000000..9b7e38f3e --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/ewma_config.ts @@ -0,0 +1,27 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Stored parameters for the gas-price EWMA trade penalty. + * + * `ExpiryMarket` holds the evolving `EwmaState`; this config holds the + * admin-tunable knobs shared by every market. The penalty is disabled by default. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::ewma_config'; +export const EwmaConfig = new MoveStruct({ + name: `${$moduleName}::EwmaConfig`, + fields: { + /** Smoothing factor for the gas-price mean and variance; higher reacts faster. */ + alpha: bcs.u64(), + /** Standard deviations above the smoothed mean required before a penalty applies. */ + z_score_threshold: bcs.u64(), + /** Per-unit fee added to a penalized trade's trading fee. */ + penalty_rate: bcs.u64(), + /** Master switch; no penalty applies while false. */ + enabled: bcs.bool(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash.ts new file mode 100644 index 000000000..44722a1f6 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash.ts @@ -0,0 +1,26 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Expiry-local DUSDC custody and unresolved rebate-reserve accounting. + * + * This leaf owns cash balance arithmetic and the trading-fee basis used to reserve + * cash for loss rebates. It does not decide payment eligibility, pool allocation, + * or market phase sequencing; `ExpiryMarket` decides when each cash operation is + * allowed and supplies the relevant payout liability. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as balance from './deps/sui/balance.js'; +import * as expiry_cash_config from './expiry_cash_config.js'; +const $moduleName = '@local-pkg/deepbook_predict::expiry_cash'; +export const ExpiryCash = new MoveStruct({ + name: `${$moduleName}::ExpiryCash`, + fields: { + cash_balance: balance.Balance, + unresolved_trading_fees_paid: bcs.u64(), + config: expiry_cash_config.ExpiryCashConfig, + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash_config.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash_config.ts new file mode 100644 index 000000000..9ab1fbc35 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_cash_config.ts @@ -0,0 +1,22 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Stored expiry-cash policy config. + * + * ProtocolConfig owns the current global template. Each ExpiryCash stores a + * snapshot initialized from that template, so later admin updates do not change + * active expiry rebate-reserve accounting. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::expiry_cash_config'; +export const ExpiryCashConfig = new MoveStruct({ + name: `${$moduleName}::ExpiryCashConfig`, + fields: { + /** Fraction of aggregate expiry trading fees reserved for loss rebates. */ + trading_loss_rebate_rate: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_market.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_market.ts new file mode 100644 index 000000000..82f61d4e5 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/expiry_market.ts @@ -0,0 +1,1050 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Per-expiry Predict market. + * + * An ExpiryMarket is the hot shared object for one expiry. It owns trade + * execution, strike exposure state, and an embedded expiry-cash custody component, + * plus local sponsor-funded fee incentives. Live oracle validation is delegated to + * `pricing::load_live_pricer`; this module owns market flow policy and then passes + * loaded `Pricer` snapshots into exposure business logic. Pool-wide PLP accounting + * and profit accounting remain outside this module. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as expiry_cash from './expiry_cash.js'; +import * as balance from './deps/sui/balance.js'; +import * as strike_exposure from './strike_exposure.js'; +import * as ewma from './ewma.js'; +const $moduleName = '@local-pkg/deepbook_predict::expiry_market'; +export const ExpiryMarket = new MoveStruct({ + name: `${$moduleName}::ExpiryMarket`, + fields: { + id: bcs.Address, + /** Propbook underlying this market was created for. */ + propbook_underlying_id: bcs.u32(), + expiry: bcs.u64(), + /** Terminal settlement price once exact Propbook expiry data has been recorded. */ + settlement_price: bcs.option(bcs.u64()), + /** DUSDC custody, payout backing, and unresolved rebate reserve basis. */ + cash: expiry_cash.ExpiryCash, + /** Sponsor-funded DUSDC available to subsidize this market's taker fees. */ + fee_incentive_balance: balance.Balance, + /** Exposure lifecycle state for this expiry's strike ticks. */ + strike_exposure: strike_exposure.StrikeExposure, + /** Smoothed gas-price stats backing the congestion trade penalty. */ + ewma: ewma.EwmaState, + /** + * When true, new mints on this expiry abort. Other flows stay available. Admin + * sets/unsets it (version-gated); a `PauseCap` holder can force it true one-way + * through the registry (ungated kill switch). + */ + mint_paused: bcs.bool(), + }, +}); +export interface IdArguments { + market: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [market: RawTransactionArgument]; +} +/** Return the expiry market object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookUnderlyingIdArguments { + market: RawTransactionArgument; +} +export interface PropbookUnderlyingIdOptions { + package?: string; + arguments: PropbookUnderlyingIdArguments | [market: RawTransactionArgument]; +} +/** Return the Propbook underlying this market was created for. */ +export function propbookUnderlyingId(options: PropbookUnderlyingIdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'propbook_underlying_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ExpiryArguments { + market: RawTransactionArgument; +} +export interface ExpiryOptions { + package?: string; + arguments: ExpiryArguments | [market: RawTransactionArgument]; +} +/** Return the expiry timestamp in milliseconds. */ +export function expiry(options: ExpiryOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'expiry', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CashBalanceArguments { + market: RawTransactionArgument; +} +export interface CashBalanceOptions { + package?: string; + arguments: CashBalanceArguments | [market: RawTransactionArgument]; +} +/** Return DUSDC currently held by this expiry. */ +export function cashBalance(options: CashBalanceOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'cash_balance', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RebateReserveArguments { + market: RawTransactionArgument; +} +export interface RebateReserveOptions { + package?: string; + arguments: RebateReserveArguments | [market: RawTransactionArgument]; +} +/** Return DUSDC reserved for unresolved trading loss rebates. */ +export function rebateReserve(options: RebateReserveOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'rebate_reserve', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface FeeIncentiveBalanceArguments { + market: RawTransactionArgument; +} +export interface FeeIncentiveBalanceOptions { + package?: string; + arguments: FeeIncentiveBalanceArguments | [market: RawTransactionArgument]; +} +/** Return sponsor-funded DUSDC available to subsidize this market's taker fees. */ +export function feeIncentiveBalance(options: FeeIncentiveBalanceOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'fee_incentive_balance', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface TradingLossRebateRateArguments { + market: RawTransactionArgument; +} +export interface TradingLossRebateRateOptions { + package?: string; + arguments: TradingLossRebateRateArguments | [market: RawTransactionArgument]; +} +/** Return the trading loss rebate rate snapshotted for this expiry. */ +export function tradingLossRebateRate(options: TradingLossRebateRateOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'trading_loss_rebate_rate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface LiquidationLtvArguments { + market: RawTransactionArgument; +} +export interface LiquidationLtvOptions { + package?: string; + arguments: LiquidationLtvArguments | [market: RawTransactionArgument]; +} +/** Return the liquidation LTV snapshotted for this expiry. */ +export function liquidationLtv(options: LiquidationLtvOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'liquidation_ltv', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MaxAdmissionLeverageArguments { + market: RawTransactionArgument; +} +export interface MaxAdmissionLeverageOptions { + package?: string; + arguments: MaxAdmissionLeverageArguments | [market: RawTransactionArgument]; +} +/** Return the max admission leverage snapshotted for this expiry. */ +export function maxAdmissionLeverage(options: MaxAdmissionLeverageOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'max_admission_leverage', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BackingBufferLambdaArguments { + market: RawTransactionArgument; +} +export interface BackingBufferLambdaOptions { + package?: string; + arguments: BackingBufferLambdaArguments | [market: RawTransactionArgument]; +} +/** Return the backing-buffer lambda snapshotted for this expiry. */ +export function backingBufferLambda(options: BackingBufferLambdaOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'backing_buffer_lambda', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ExpiryFeeWindowMsArguments { + market: RawTransactionArgument; +} +export interface ExpiryFeeWindowMsOptions { + package?: string; + arguments: ExpiryFeeWindowMsArguments | [market: RawTransactionArgument]; +} +/** Return the trade-fee ramp window snapshotted for this expiry. */ +export function expiryFeeWindowMs(options: ExpiryFeeWindowMsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'expiry_fee_window_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ExpiryFeeMaxMultiplierArguments { + market: RawTransactionArgument; +} +export interface ExpiryFeeMaxMultiplierOptions { + package?: string; + arguments: ExpiryFeeMaxMultiplierArguments | [market: RawTransactionArgument]; +} +/** Return the trade-fee ramp max multiplier snapshotted for this expiry. */ +export function expiryFeeMaxMultiplier(options: ExpiryFeeMaxMultiplierOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'expiry_fee_max_multiplier', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface TickSizeArguments { + market: RawTransactionArgument; +} +export interface TickSizeOptions { + package?: string; + arguments: TickSizeArguments | [market: RawTransactionArgument]; +} +/** + * Return the strike tick size snapshotted for this expiry. Raw strikes are derived + * off-chain / by the SDK as `tick * tick_size`. + */ +export function tickSize(options: TickSizeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'tick_size', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface AdmissionTickSizeArguments { + market: RawTransactionArgument; +} +export interface AdmissionTickSizeOptions { + package?: string; + arguments: AdmissionTickSizeArguments | [market: RawTransactionArgument]; +} +/** Return the coarser raw-price step that new finite mint boundaries must align to. */ +export function admissionTickSize(options: AdmissionTickSizeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'admission_tick_size', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ReferenceTickArguments { + market: RawTransactionArgument; +} +export interface ReferenceTickOptions { + package?: string; + arguments: ReferenceTickArguments | [market: RawTransactionArgument]; +} +/** + * Return the reference fine-grid tick admitted for this expiry, if it has been + * set. + */ +export function referenceTick(options: ReferenceTickOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'reference_tick', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ReferenceTickSourceTimestampMsArguments { + market: RawTransactionArgument; +} +export interface ReferenceTickSourceTimestampMsOptions { + package?: string; + arguments: ReferenceTickSourceTimestampMsArguments | [market: RawTransactionArgument]; +} +/** Return the exact Propbook Pyth source timestamp used to derive `reference_tick`. */ +export function referenceTickSourceTimestampMs(options: ReferenceTickSourceTimestampMsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'reference_tick_source_timestamp_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PayoutLiabilityArguments { + market: RawTransactionArgument; +} +export interface PayoutLiabilityOptions { + package?: string; + arguments: PayoutLiabilityArguments | [market: RawTransactionArgument]; +} +/** + * Return buffered live reserve, or exact remaining settled payout liability once + * materialized. + */ +export function payoutLiability(options: PayoutLiabilityOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'payout_liability', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RequiredCashArguments { + market: RawTransactionArgument; +} +export interface RequiredCashOptions { + package?: string; + arguments: RequiredCashArguments | [market: RawTransactionArgument]; +} +/** Return cash required to cover payout liability plus unresolved rebate reserve. */ +export function requiredCash(options: RequiredCashOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'required_cash', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface LoadLivePricerArguments { + market: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; + bsSpot: RawTransactionArgument; + bsForward: RawTransactionArgument; + bsSvi: RawTransactionArgument; +} +export interface LoadLivePricerOptions { + package?: string; + arguments: + | LoadLivePricerArguments + | [ + market: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + bsSpot: RawTransactionArgument, + bsForward: RawTransactionArgument, + bsSvi: RawTransactionArgument, + ]; +} +/** + * Load a PTB-local live pricing snapshot for this market. + * + * The returned `Pricer` is bound to `market.id()` and can be passed into live + * mint, redeem, liquidation, and NAV functions in the same transaction. + */ +export function loadLivePricer(options: LoadLivePricerOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, null, null, null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = [ + 'market', + 'config', + 'propbookRegistry', + 'pyth', + 'bsSpot', + 'bsForward', + 'bsSvi', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'load_live_pricer', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CurrentNavArguments { + market: RawTransactionArgument; + pricer: RawTransactionArgument; +} +export interface CurrentNavOptions { + package?: string; + arguments: + | CurrentNavArguments + | [market: RawTransactionArgument, pricer: RawTransactionArgument]; +} +/** + * Return this expiry market's exact live NAV: free cash minus the exact per-order + * live liability, floored at zero. This is structurally the live primitive for a + * market-bound `Pricer`; an empty or order-free live market returns free cash + * (zero liability). + * + * A pure read with no backing assert: backing is owned by the payout-tree reserve + * and proven on every trade, and the `max(0, ·)` cash floor marks a degenerate + * (underwater) market at 0 — the correct per-market limited-recourse value, never + * negative. `load_live_pricer` binds the propbook feeds to this market's current + * Propbook registry mapping, rejects a past-expiry market, and gates oracle + * freshness. + * + * A past-expiry market that has not settled cannot produce this pricer. There is + * no solvency-safe NAV for an unsettled past-expiry market: the flush uses one + * mark for both supply and withdraw, so the mark must equal the + * settlement-dependent true value. Flows that branch on settlement call + * `ensure_settled` first, using Propbook's exact Pyth timestamp at expiry; if no + * exact spot exists yet, the live-pricing liveness abort remains the correct + * failure mode. + */ +export function currentNav(options: CurrentNavOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['market', 'pricer']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'current_nav', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MintPausedArguments { + market: RawTransactionArgument; +} +export interface MintPausedOptions { + package?: string; + arguments: MintPausedArguments | [market: RawTransactionArgument]; +} +/** Return whether minting is currently paused on this expiry market. */ +export function mintPaused(options: MintPausedOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['market']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'mint_paused', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MintExactQuantityArguments { + market: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + pricer: RawTransactionArgument; + lowerTick: RawTransactionArgument; + higherTick: RawTransactionArgument; + quantity: RawTransactionArgument; + leverage: RawTransactionArgument; + maxCost: RawTransactionArgument; + maxProbability: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface MintExactQuantityOptions { + package?: string; + arguments: + | MintExactQuantityArguments + | [ + market: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + pricer: RawTransactionArgument, + lowerTick: RawTransactionArgument, + higherTick: RawTransactionArgument, + quantity: RawTransactionArgument, + leverage: RawTransactionArgument, + maxCost: RawTransactionArgument, + maxProbability: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Mint an exact live position quantity against this expiry market. + * + * Requires the running package version to be at or above the protocol version + * watermark, per-market mint pause to be off, trading globally enabled, a valid + * account owner auth, a market-bound live `Pricer`, and enough expiry cash to back + * the post-mint max payout and rebate reserve. Leverage is continuous (any + * `L >= 1`); the derived static barrier `b = floor_shares/quantity` must sit below + * the at-entry liquidation threshold so the order is not instantly knockable. Mint + * fees are paid by routing a withdraw through the loaded account. The position's + * strike range is the tick pair `(lower_tick, higher_tick]` (`lower_tick = 0` is + * `-inf`, `higher_tick = pos_inf_tick` is `+inf`); the SDK converts raw strikes to + * ticks. `max_cost` caps the all-in DUSDC withdrawal, while `max_probability` caps + * the quoted per-contract probability before fees. Callers can pass + * `std::u64::max_value!()` for either uncapped guard. Returns the minted order ID + * for future order-scoped flows. + */ +export function mintExactQuantity(options: MintExactQuantityOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + 'u64', + 'u64', + 'u64', + 'u64', + 'u64', + 'u64', + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'market', + 'wrapper', + 'auth', + 'config', + 'pricer', + 'lowerTick', + 'higherTick', + 'quantity', + 'leverage', + 'maxCost', + 'maxProbability', + 'root', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'mint_exact_quantity', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MintExactAmountArguments { + market: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + pricer: RawTransactionArgument; + lowerTick: RawTransactionArgument; + higherTick: RawTransactionArgument; + amount: RawTransactionArgument; + minQuantity: RawTransactionArgument; + leverage: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface MintExactAmountOptions { + package?: string; + arguments: + | MintExactAmountArguments + | [ + market: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + pricer: RawTransactionArgument, + lowerTick: RawTransactionArgument, + higherTick: RawTransactionArgument, + amount: RawTransactionArgument, + minQuantity: RawTransactionArgument, + leverage: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Mint the largest lot-rounded live position whose net premium fits inside + * `amount`, aborting if the resulting quantity is below `min_quantity`. + * + * Fees, builder fees, and EWMA congestion penalties are charged on top of + * `amount`. The sizing budget is first capped to the account's available DUSDC + * after settlement; fees still require additional available DUSDC at payment time. + * Any unspent premium dust remains in the account because order quantity must be + * an integer number of `position_lot_size` lots. + */ +export function mintExactAmount(options: MintExactAmountOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + 'u64', + 'u64', + 'u64', + 'u64', + 'u64', + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'market', + 'wrapper', + 'auth', + 'config', + 'pricer', + 'lowerTick', + 'higherTick', + 'amount', + 'minQuantity', + 'leverage', + 'root', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'mint_exact_amount', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RedeemLiveArguments { + market: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + pricer: RawTransactionArgument; + orderId: RawTransactionArgument; + closeQuantity: RawTransactionArgument; + minProbability: RawTransactionArgument; + minProceeds: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface RedeemLiveOptions { + package?: string; + arguments: + | RedeemLiveArguments + | [ + market: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + pricer: RawTransactionArgument, + orderId: RawTransactionArgument, + closeQuantity: RawTransactionArgument, + minProbability: RawTransactionArgument, + minProceeds: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Redeem a live order you hold account authority over. + * + * A live order is priced and closed (partial or full); a liquidated tombstone is + * fully closed with zero payout. Settled orders must use `redeem_settled`. Returns + * `(closed_order_id, replacement_order_id)`; a replacement is present only when a + * live partial close leaves quantity open. + * + * Two close-side slippage floors, the mirror of mint's `max_probability` / + * `max_cost` pair; pass `0` to disable either. `min_probability` floors the quoted + * per-contract range probability (same units as mint's `max_probability`). + * `min_proceeds` floors the all-in net DUSDC credited to the account + * (`redeem_amount` minus trading fee, builder fee, and EWMA penalty), the mirror + * of mint's all-in `max_cost`. Both only gate the live-priced path — a liquidated + * tombstone closes at zero payout regardless, since its value is deterministic, + * not market-quoted. + */ +export function redeemLive(options: RedeemLiveOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + 'u256', + 'u64', + 'u64', + 'u64', + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'market', + 'wrapper', + 'auth', + 'config', + 'pricer', + 'orderId', + 'closeQuantity', + 'minProbability', + 'minProceeds', + 'root', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'redeem_live', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RedeemSettledArguments { + market: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; + orderId: RawTransactionArgument; + closeQuantity: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface RedeemSettledOptions { + package?: string; + arguments: + | RedeemSettledArguments + | [ + market: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + orderId: RawTransactionArgument, + closeQuantity: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Redeem a settled order you hold account authority over. + * + * The market must be settled already; this flow does not run live pricing or new + * liquidation. Liquidated tombstones clear with zero payout. Requires a full + * close. This owner-auth path remains available even when Predict app-auth + * automation is deauthorized in the account registry. + */ +export function redeemSettled(options: RedeemSettledOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + null, + 'u256', + 'u64', + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'market', + 'wrapper', + 'auth', + 'config', + 'propbookRegistry', + 'pyth', + 'orderId', + 'closeQuantity', + 'root', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'redeem_settled', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RedeemSettledPermissionlessArguments { + market: RawTransactionArgument; + accountRegistry: RawTransactionArgument; + wrapper: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; + orderId: RawTransactionArgument; + closeQuantity: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface RedeemSettledPermissionlessOptions { + package?: string; + arguments: + | RedeemSettledPermissionlessArguments + | [ + market: RawTransactionArgument, + accountRegistry: RawTransactionArgument, + wrapper: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + orderId: RawTransactionArgument, + closeQuantity: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Permissionlessly redeem a settled order without account-owner authority. + * + * This keeper path uses Predict app-auth from the account registry, so + * `deauthorize_app` disables this automation. Owners can still use + * `redeem_settled` with owner auth to redeem their own settled positions. + */ +export function redeemSettledPermissionless(options: RedeemSettledPermissionlessOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + null, + 'u256', + 'u64', + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'market', + 'accountRegistry', + 'wrapper', + 'config', + 'propbookRegistry', + 'pyth', + 'orderId', + 'closeQuantity', + 'root', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'redeem_settled_permissionless', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface LiquidateArguments { + market: RawTransactionArgument; + config: RawTransactionArgument; + pricer: RawTransactionArgument; + budget: RawTransactionArgument; +} +export interface LiquidateOptions { + package?: string; + arguments: + | LiquidateArguments + | [ + market: RawTransactionArgument, + config: RawTransactionArgument, + pricer: RawTransactionArgument, + budget: RawTransactionArgument, + ]; +} +/** + * Run one bounded liquidation pass over active leveraged orders. + * + * The liquidation book selects up to `budget` candidates and returns the number of + * orders liquidated. It does not touch accounts; users clear their liquidated + * position later through `redeem_live` or `redeem_settled`, receiving no payout. + */ +export function liquidate(options: LiquidateOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['market', 'config', 'pricer', 'budget']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'liquidate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface LiquidateOrderArguments { + market: RawTransactionArgument; + config: RawTransactionArgument; + pricer: RawTransactionArgument; + orderId: RawTransactionArgument; +} +export interface LiquidateOrderOptions { + package?: string; + arguments: + | LiquidateOrderArguments + | [ + market: RawTransactionArgument, + config: RawTransactionArgument, + pricer: RawTransactionArgument, + orderId: RawTransactionArgument, + ]; +} +/** Try to liquidate one active leveraged order by ID. */ +export function liquidateOrder(options: LiquidateOrderOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, 'u256'] satisfies (string | null)[]; + const parameterNames = ['market', 'config', 'pricer', 'orderId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'liquidate_order', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetReferenceTickArguments { + market: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; +} +export interface SetReferenceTickOptions { + package?: string; + arguments: + | SetReferenceTickArguments + | [ + market: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + ]; +} +/** + * Set this expiry's reference fine-grid tick from the exact previous-window + * Propbook Pyth observation. The source observation must be inserted into the feed + * at `reference_tick_source_timestamp_ms` before this call, and the normalized + * spot is floored to the market's `tick_size`. + */ +export function setReferenceTick(options: SetReferenceTickOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null] satisfies (string | null)[]; + const parameterNames = ['market', 'config', 'propbookRegistry', 'pyth']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'set_reference_tick', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetMintPausedArguments { + market: RawTransactionArgument; + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + paused: RawTransactionArgument; +} +export interface SetMintPausedOptions { + package?: string; + arguments: + | SetMintPausedArguments + | [ + market: RawTransactionArgument, + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + paused: RawTransactionArgument, + ]; +} +/** + * Set whether new mints are paused on this expiry market. Admin-only and + * version-gated. A `PauseCap` holder can force-engage the pause one-way under a + * version freeze via `registry::pause_expiry_market_mint_pause_cap`. + */ +export function setMintPaused(options: SetMintPausedOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, 'bool'] satisfies (string | null)[]; + const parameterNames = ['market', 'config', 'AdminCap', 'paused']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'expiry_market', + function: 'set_mint_paused', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/liquidation_book.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/liquidation_book.ts new file mode 100644 index 000000000..4a10640ca --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/liquidation_book.ts @@ -0,0 +1,52 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Priority-sorted liquidation index for active leveraged Predict orders. + * + * The active index stores order IDs in ascending order. `Order` encodes its + * liquidation priority in the high bits, so the front of this index contains the + * orders that should be checked first. Beyond serving liquidation candidates, the + * book owns exactly one valuation read: `correction_value` walks its active + * leveraged set to value the NAV floor-correction term — the only place this + * module touches pricing/tick/floor math, and it does so through a caller-supplied + * `Pricer`, never owning the pricing model itself. It does not own payout backing, + * cash, or account positions. Liquidated tombstones persist until the holder + * redeems the worthless order and clears their account position. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as table from './deps/sui/table.js'; +import * as table_1 from './deps/sui/table.js'; +const $moduleName = '@local-pkg/deepbook_predict::liquidation_book'; +export const LiquidationBook = new MoveStruct({ + name: `${$moduleName}::LiquidationBook`, + fields: { + pages: table.Table, + /** Page IDs in ascending order-ID order. */ + page_ids: bcs.vector(bcs.u64()), + /** Maximum order ID stored in each page, aligned with `page_ids`. */ + max_order_ids: bcs.vector(bcs.u256()), + next_page_id: bcs.u64(), + active_order_count: bcs.u64(), + /** Last order ID visited by the passive liquidation scan. */ + passive_watermark: bcs.option(bcs.u256()), + /** Orders already removed from live exposure indexes but not yet redeemed. */ + liquidated_orders: table_1.Table, + }, +}); +export const OrderIdPage = new MoveStruct({ + name: `${$moduleName}::OrderIdPage`, + fields: { + order_ids: bcs.vector(bcs.u256()), + }, +}); +export const ScanCursor = new MoveStruct({ + name: `${$moduleName}::ScanCursor`, + fields: { + page_ix: bcs.u64(), + offset: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/lp_book.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/lp_book.ts new file mode 100644 index 000000000..08202a417 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/lp_book.ts @@ -0,0 +1,66 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * LP request book and share issuance for the pool vault. + * + * `LpBook` owns the PLP treasury cap plus the async supply/withdraw queues. `plp` + * owns the shared `PoolVault`, valuation, and pool cash accounting; it delegates + * request/cancel and frozen-mark queue drains here. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as table from './deps/sui/table.js'; +import * as balance from './deps/sui/balance.js'; +import * as coin from './deps/sui/coin.js'; +import * as balance_1 from './deps/sui/balance.js'; +const $moduleName = '@local-pkg/deepbook_predict::lp_book'; +export const RequestQueue = new MoveStruct({ + name: `${$moduleName}::RequestQueue`, + fields: { + pages: table.Table, + head_page_id: bcs.option(bcs.u64()), + tail_page_id: bcs.option(bcs.u64()), + next_index: bcs.u64(), + pending: bcs.u64(), + escrow: balance.Balance, + }, +}); +export const LpBook = new MoveStruct({ + name: `${$moduleName}::LpBook`, + fields: { + treasury_cap: coin.TreasuryCap, + supply_queue: RequestQueue, + withdraw_queue: RequestQueue, + /** + * Permanent minimum-liquidity shares minted once at genesis (`plp::lock_capital`). + * Held here with no withdraw path, so `total_supply` stays > 0 for the life of the + * pool and the supply==0 bootstrap branch is unreachable. Withdrawal-rounding dust + * accrues to this position. + */ + locked_lp: balance_1.Balance, + }, +}); +export const RequestEntry = new MoveStruct({ + name: `${$moduleName}::RequestEntry`, + fields: { + index: bcs.u64(), + /** + * Owning account, carried so a fill can attribute to the account directly rather + * than only the derived `recipient` address (address is not invertible). + */ + account_id: bcs.Address, + recipient: bcs.Address, + amount: bcs.u64(), + }, +}); +export const RequestPage = new MoveStruct({ + name: `${$moduleName}::RequestPage`, + fields: { + prev: bcs.option(bcs.u64()), + next: bcs.option(bcs.u64()), + entries: bcs.vector(RequestEntry), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/market_lifecycle_cap.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/market_lifecycle_cap.ts new file mode 100644 index 000000000..8d19139a4 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/market_lifecycle_cap.ts @@ -0,0 +1,68 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Market lifecycle capability. Authorizes market lifecycle operations without + * granting any oracle write authority. `Registry` owns the allowlist of valid + * lifecycle caps and the admin mint/revoke entrypoints; this module owns the cap + * object and the transaction-local proof consumed by cross-module lifecycle + * actions. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +const $moduleName = '@local-pkg/deepbook_predict::market_lifecycle_cap'; +export const MarketLifecycleCap = new MoveStruct({ + name: `${$moduleName}::MarketLifecycleCap`, + fields: { + id: bcs.Address, + }, +}); +export const MarketLifecycleProof = new MoveStruct({ + name: `${$moduleName}::MarketLifecycleProof`, + fields: { + dummy_field: bcs.bool(), + }, +}); +export interface IdArguments { + cap: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [cap: RawTransactionArgument]; +} +/** Return the lifecycle cap object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'market_lifecycle_cap', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface DestroyArguments { + cap: RawTransactionArgument; +} +export interface DestroyOptions { + package?: string; + arguments: DestroyArguments | [cap: RawTransactionArgument]; +} +/** Destroy a `MarketLifecycleCap` the holder no longer needs. */ +export function destroy(options: DestroyOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'market_lifecycle_cap', + function: 'destroy', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/market_manager.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/market_manager.ts new file mode 100644 index 000000000..a57d1aed7 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/market_manager.ts @@ -0,0 +1,73 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Market identity and deployment cadence manager for Predict. + * + * `Registry` owns this state and delegates market admission to it. Fixed cadence + * IDs, periods, and rank order are upgrade-required. Underlying rows, cadence + * deployment terms, and per-underlying watermarks are stored here. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as table from './deps/sui/table.js'; +import * as table_1 from './deps/sui/table.js'; +const $moduleName = '@local-pkg/deepbook_predict::market_manager'; +export const MarketKey = new MoveStruct({ + name: `${$moduleName}::MarketKey`, + fields: { + propbook_underlying_id: bcs.u32(), + expiry: bcs.u64(), + }, +}); +export const MarketManager = new MoveStruct({ + name: `${$moduleName}::MarketManager`, + fields: { + /** Propbook underlying ID -> deployment watermarks. */ + underlying_configs: table.Table, + /** Created markets keyed by `(propbook_underlying_id, expiry)`. */ + market_ids: table_1.Table, + }, +}); +export const CadenceConfig = new MoveStruct({ + name: `${$moduleName}::CadenceConfig`, + fields: { + /** Raw-price-per-tick factor snapshotted into each created market. */ + tick_size: bcs.u64(), + /** Coarser raw-price step that new finite mint boundaries must align to. */ + admission_tick_size: bcs.u64(), + /** + * DUSDC pool allocation cap snapshotted into pool accounting for each created + * expiry. + */ + max_expiry_allocation: bcs.u64(), + /** + * Minimum DUSDC cash target snapshotted into pool accounting for each created + * expiry. + */ + initial_expiry_cash: bcs.u64(), + /** + * Number of future cadence slots that deployment may keep filled. Zero disables + * this cadence; enabled cadences are capped by an upgrade-required bound. + */ + window_size: bcs.u64(), + }, +}); +export const DeployableMarket = new MoveStruct({ + name: `${$moduleName}::DeployableMarket`, + fields: { + expiry: bcs.u64(), + cadence: CadenceConfig, + }, +}); +export const UnderlyingMarketConfig = new MoveStruct({ + name: `${$moduleName}::UnderlyingMarketConfig`, + fields: { + /** Deployment config indexed by cadence ID. */ + cadences: bcs.vector(CadenceConfig), + /** Highest deployed expiry timestamp indexed by cadence ID. */ + last_deployed_expiries: bcs.vector(bcs.u64()), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/order.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/order.ts new file mode 100644 index 000000000..8da51c808 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/order.ts @@ -0,0 +1,25 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Immutable contract terms encoded in a Predict order ID. + * + * An `Order` represents the durable contract terms needed after mint: the lower + * and higher strike ticks, quantity, the static floor amount (`floor_shares = F`), + * and the expiry-local sequence. Mint-only inputs such as entry probability, + * leverage, net premium, and fee policy intentionally live outside this module. + * The packed ID is the single source of truth at protocol boundaries; raw strike + * conversion (through the owning market's `tick_size`) is interpreted by + * `StrikeExposure`. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::order'; +export const Order = new MoveStruct({ + name: `${$moduleName}::Order`, + fields: { + id: bcs.u256(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/order_events.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/order_events.ts new file mode 100644 index 000000000..58dc77071 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/order_events.ts @@ -0,0 +1,117 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Order-lifecycle and liquidation events for Predict. + * + * Hot-path events stay lean: each carries the deltas and identities a consumer + * needs to reconstruct money flows off-chain, with no absolute balances. + * `order_id` joins minted, redeemed, and liquidated rows for one position; the + * network envelope supplies timestamp and sender, so neither is a field. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::order_events'; +export const OrderMinted = new MoveStruct({ + name: `${$moduleName}::OrderMinted`, + fields: { + expiry_market_id: bcs.Address, + account_id: bcs.Address, + order_id: bcs.u256(), + /** + * Stable economic-position handle: the original mint's `order_id`, carried forward + * unchanged across partial-close replacements. Equals `order_id` here. + */ + position_root_id: bcs.u256(), + owner: bcs.Address, + /** + * Canonical strike range as absolute ticks: `lower_tick` (`0` = `-inf`) and + * `higher_tick` (`pos_inf_tick` = `+inf`). Raw strikes are the derived display + * form, `tick * tick_size` with the `tick_size` from `MarketCreated`. + */ + lower_tick: bcs.u64(), + higher_tick: bcs.u64(), + leverage: bcs.u64(), + /** 1e9-scaled range probability quoted at entry. */ + entry_probability: bcs.u64(), + quantity: bcs.u64(), + /** Net premium the user paid into LP backing, in DUSDC base units. */ + net_premium: bcs.u64(), + /** Full trading fee collected by the expiry, including any sponsor-paid subsidy. */ + trading_fee: bcs.u64(), + /** Portion of `trading_fee` paid from expiry-local fee incentives. */ + fee_incentive_subsidy: bcs.u64(), + builder_fee: bcs.u64(), + /** EWMA gas-price congestion surcharge retained by the pool, in DUSDC base units. */ + penalty_fee: bcs.u64(), + builder_code_id: bcs.option(bcs.Address), + }, +}); +export const LiveOrderRedeemed = new MoveStruct({ + name: `${$moduleName}::LiveOrderRedeemed`, + fields: { + expiry_market_id: bcs.Address, + account_id: bcs.Address, + order_id: bcs.u256(), + /** + * Stable economic-position handle, constant across the replacement chain. On a + * partial close the replacement inherits this same root. + */ + position_root_id: bcs.u256(), + owner: bcs.Address, + quantity_closed: bcs.u64(), + /** `0` means the position was fully closed. */ + remaining_quantity: bcs.u64(), + /** New order ID minted to carry the remainder on a partial live close. */ + replacement_order_id: bcs.option(bcs.u256()), + /** Redeem value before fees, after any floor deduction. */ + redeem_amount: bcs.u64(), + trading_fee: bcs.u64(), + builder_fee: bcs.u64(), + /** EWMA gas-price congestion surcharge retained by the pool, in DUSDC base units. */ + penalty_fee: bcs.u64(), + builder_code_id: bcs.option(bcs.Address), + }, +}); +export const SettledOrderRedeemed = new MoveStruct({ + name: `${$moduleName}::SettledOrderRedeemed`, + fields: { + expiry_market_id: bcs.Address, + account_id: bcs.Address, + order_id: bcs.u256(), + /** Stable economic-position handle, constant across the replacement chain. */ + position_root_id: bcs.u256(), + owner: bcs.Address, + quantity_closed: bcs.u64(), + settlement_price: bcs.u64(), + payout_amount: bcs.u64(), + }, +}); +export const LiquidatedOrderRedeemed = new MoveStruct({ + name: `${$moduleName}::LiquidatedOrderRedeemed`, + fields: { + expiry_market_id: bcs.Address, + account_id: bcs.Address, + order_id: bcs.u256(), + /** Stable economic-position handle, constant across the replacement chain. */ + position_root_id: bcs.u256(), + owner: bcs.Address, + quantity_closed: bcs.u64(), + }, +}); +export const OrderLiquidated = new MoveStruct({ + name: `${$moduleName}::OrderLiquidated`, + fields: { + expiry_market_id: bcs.Address, + order_id: bcs.u256(), + quantity: bcs.u64(), + /** Probability-weighted value checked against the liquidation threshold. */ + gross_value: bcs.u64(), + /** Current contract floor in DUSDC base units. */ + floor_amount: bcs.u64(), + /** 1e9-scaled floor-to-live-value threshold used for this expiry. */ + liquidation_ltv: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/pause_cap.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/pause_cap.ts new file mode 100644 index 000000000..aa45a1c15 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/pause_cap.ts @@ -0,0 +1,60 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Emergency pause capability. `Registry` owns the allowlist of valid pause caps + * and the admin mint/revoke entrypoints; this module owns only the cap object + * itself. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +const $moduleName = '@local-pkg/deepbook_predict::pause_cap'; +export const PauseCap = new MoveStruct({ + name: `${$moduleName}::PauseCap`, + fields: { + id: bcs.Address, + }, +}); +export interface IdArguments { + cap: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [cap: RawTransactionArgument]; +} +/** Return the pause cap object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pause_cap', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface DestroyArguments { + cap: RawTransactionArgument; +} +export interface DestroyOptions { + package?: string; + arguments: DestroyArguments | [cap: RawTransactionArgument]; +} +/** Destroy a `PauseCap` the holder no longer needs. */ +export function destroy(options: DestroyOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pause_cap', + function: 'destroy', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/plp.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/plp.ts new file mode 100644 index 000000000..0a546ad65 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/plp.ts @@ -0,0 +1,981 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * PLP token and pool vault. + * + * PoolVault owns the PLP treasury cap, the pooled DEEP staked by accounts, idle + * DUSDC, the protocol reserve, sponsor-funded fee incentives, per-expiry cash + * accounting, and the async LP supply/withdraw queues. It coordinates the + * full-pool NAV valuation (a hot-potato aggregation over every active market) and + * the unified per-market cash flow (initial funding, live rebalance/sweep, and + * settled-market sweep with terminal profit materialization). LPs queue + * supply/withdraw requests routed through a loaded Account; the daily flush + * (`finish_flush`) drains them at the frozen pool NAV, minting/burning PLP and + * delivering fills to each account via the balance accumulator. PLP incentives + * moved to a separate staking contract; DEEP staking is an unrelated trading + * feature. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as balance from './deps/sui/balance.js'; +import * as balance_1 from './deps/sui/balance.js'; +import * as balance_2 from './deps/sui/balance.js'; +import * as lp_book from './lp_book.js'; +import * as pool_accounting from './pool_accounting.js'; +const $moduleName = '@local-pkg/deepbook_predict::plp'; +export const PLP = new MoveStruct({ + name: `${$moduleName}::PLP`, + fields: { + dummy_field: bcs.bool(), + }, +}); +export const PoolVault = new MoveStruct({ + name: `${$moduleName}::PoolVault`, + fields: { + id: bcs.Address, + /** + * Protocol-owned DUSDC (the materialized terminal-profit cut) excluded from PLP + * redemption. + */ + protocol_reserve_balance: balance.Balance, + /** Sponsor-funded DUSDC reserved for taker fee sponsorship, excluded from PLP NAV. */ + fee_incentive_reserve: balance_1.Balance, + /** + * Pooled DEEP staked by all accounts for trading benefits. Per-account + * active/inactive amounts are mirrored in Predict account data. + */ + staked_deep: balance_2.Balance, + /** PLP share issuance plus queued supply/withdraw escrow. */ + lp: lp_book.LpBook, + /** Idle DUSDC custody, registered expiries, and per-expiry cash-flow rows. */ + expiry_accounting: pool_accounting.Ledger, + }, +}); +export const PoolValuation = new MoveStruct({ + name: `${$moduleName}::PoolValuation`, + fields: { + pool_vault_id: bcs.Address, + /** Active expiry markets snapshotted at start; every one must be valued. */ + expected_expiry_markets: bcs.vector(bcs.Address), + /** Markets valued so far this flow; folded against `expected` at finish. */ + valued_expiry_markets: bcs.vector(bcs.Address), + /** Running Σ of each valued market's NAV (settled markets contribute 0). */ + total_nav: bcs.u64(), + }, +}); +export interface IdArguments { + vault: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [vault: RawTransactionArgument]; +} +/** Return the pool vault object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface StakedDeepArguments { + vault: RawTransactionArgument; +} +export interface StakedDeepOptions { + package?: string; + arguments: StakedDeepArguments | [vault: RawTransactionArgument]; +} +/** Return DEEP staked by accounts and held in custody by the pool. */ +export function stakedDeep(options: StakedDeepOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'staked_deep', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface IdleBalanceArguments { + vault: RawTransactionArgument; +} +export interface IdleBalanceOptions { + package?: string; + arguments: IdleBalanceArguments | [vault: RawTransactionArgument]; +} +/** Return idle DUSDC held by the pool (available for funding and withdrawals). */ +export function idleBalance(options: IdleBalanceOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'idle_balance', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ProtocolReserveBalanceArguments { + vault: RawTransactionArgument; +} +export interface ProtocolReserveBalanceOptions { + package?: string; + arguments: ProtocolReserveBalanceArguments | [vault: RawTransactionArgument]; +} +/** Return protocol-owned DUSDC excluded from PLP redemption. */ +export function protocolReserveBalance(options: ProtocolReserveBalanceOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'protocol_reserve_balance', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface FeeIncentiveReserveArguments { + vault: RawTransactionArgument; +} +export interface FeeIncentiveReserveOptions { + package?: string; + arguments: FeeIncentiveReserveArguments | [vault: RawTransactionArgument]; +} +/** Return sponsor-funded DUSDC available for future fee-incentive allocation. */ +export function feeIncentiveReserve(options: FeeIncentiveReserveOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'fee_incentive_reserve', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PlpTotalSupplyArguments { + vault: RawTransactionArgument; +} +export interface PlpTotalSupplyOptions { + package?: string; + arguments: PlpTotalSupplyArguments | [vault: RawTransactionArgument]; +} +/** Return the total PLP share supply outstanding. */ +export function plpTotalSupply(options: PlpTotalSupplyOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'plp_total_supply', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SupplyRequestsPendingArguments { + vault: RawTransactionArgument; +} +export interface SupplyRequestsPendingOptions { + package?: string; + arguments: SupplyRequestsPendingArguments | [vault: RawTransactionArgument]; +} +/** Return the count of pending (un-drained) LP supply requests. */ +export function supplyRequestsPending(options: SupplyRequestsPendingOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'supply_requests_pending', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface WithdrawRequestsPendingArguments { + vault: RawTransactionArgument; +} +export interface WithdrawRequestsPendingOptions { + package?: string; + arguments: WithdrawRequestsPendingArguments | [vault: RawTransactionArgument]; +} +/** Return the count of pending (un-drained) LP withdraw requests. */ +export function withdrawRequestsPending(options: WithdrawRequestsPendingOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'withdraw_requests_pending', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ActiveExpiryMarketsArguments { + vault: RawTransactionArgument; +} +export interface ActiveExpiryMarketsOptions { + package?: string; + arguments: ActiveExpiryMarketsArguments | [vault: RawTransactionArgument]; +} +/** Return the expiry markets still contributing active pool valuation/risk. */ +export function activeExpiryMarkets(options: ActiveExpiryMarketsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'active_expiry_markets', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ActiveLiveExpiryCountArguments { + vault: RawTransactionArgument; +} +export interface ActiveLiveExpiryCountOptions { + package?: string; + arguments: ActiveLiveExpiryCountArguments | [vault: RawTransactionArgument]; +} +/** Return the count of active pre-expiry markets that require live NAV valuation. */ +export function activeLiveExpiryCount(options: ActiveLiveExpiryCountOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'active_live_expiry_count', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ProfitBasisDebitsArguments { + vault: RawTransactionArgument; +} +export interface ProfitBasisDebitsOptions { + package?: string; + arguments: ProfitBasisDebitsArguments | [vault: RawTransactionArgument]; +} +/** Return the pricing debit side of the aggregate expiry profit basis. */ +export function profitBasisDebits(options: ProfitBasisDebitsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'profit_basis_debits', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ProfitBasisCreditsArguments { + vault: RawTransactionArgument; +} +export interface ProfitBasisCreditsOptions { + package?: string; + arguments: ProfitBasisCreditsArguments | [vault: RawTransactionArgument]; +} +/** Return the pricing credit side of the aggregate expiry profit basis. */ +export function profitBasisCredits(options: ProfitBasisCreditsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'profit_basis_credits', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PendingProtocolProfitArguments { + vault: RawTransactionArgument; +} +export interface PendingProtocolProfitOptions { + package?: string; + arguments: PendingProtocolProfitArguments | [vault: RawTransactionArgument]; +} +/** + * Return the materialized protocol cut still awaiting a physical move to the + * reserve. + */ +export function pendingProtocolProfit(options: PendingProtocolProfitOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['vault']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'pending_protocol_profit', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface StartPoolValuationArguments { + config: RawTransactionArgument; + vault: RawTransactionArgument; + lifecycleProof: RawTransactionArgument; +} +export interface StartPoolValuationOptions { + package?: string; + arguments: + | StartPoolValuationArguments + | [ + config: RawTransactionArgument, + vault: RawTransactionArgument, + lifecycleProof: RawTransactionArgument, + ]; +} +/** + * Begin a full-pool flush (NAV valuation + LP queue drain) as a market deployer, + * using a registry-generated `MarketLifecycleProof`. This is the sole flush start: + * it is cron-driven and PRIVILEGED, not permissionless (audit L8). Engages the + * protocol valuation lock — so no NAV-changing op can interleave between value + * steps — and snapshots the active expiry set every `value_expiry` must cover. The + * hot potato can only be created here, so gating the start gates the whole flush. + * + * The flush prices the pool NAV off the live oracle and `finish_flush` drains the + * LP queues at that mark, and Pyth updates (`pyth_feed::update`) are + * permissionless — so a flush-capable cap-holder who manipulates the live oracle + * in a preceding tx, then flushes, could fill their own queued supply/withdraw + * request at a mark they chose. The start is therefore gated on both current + * registry allowlisting and trust in every flush-capable holder not to manipulate + * the live oracle. The revocable `MarketLifecycleCap` (not the root `AdminCap`) + * carries this authority; admin retains a break-glass route by minting itself a + * lifecycle cap. + */ +export function startPoolValuation(options: StartPoolValuationOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null] satisfies (string | null)[]; + const parameterNames = ['config', 'vault', 'lifecycleProof']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'start_pool_valuation', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ValueExpiryArguments { + valuation: RawTransactionArgument; + vault: RawTransactionArgument; + market: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; + bsSpot: RawTransactionArgument; + bsForward: RawTransactionArgument; + bsSvi: RawTransactionArgument; +} +export interface ValueExpiryOptions { + package?: string; + arguments: + | ValueExpiryArguments + | [ + valuation: RawTransactionArgument, + vault: RawTransactionArgument, + market: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + bsSpot: RawTransactionArgument, + bsForward: RawTransactionArgument, + bsSvi: RawTransactionArgument, + ]; +} +/** + * Run the per-market cash flow for one snapshotted market, then fold its NAV into + * the running total. The market must be in the snapshot and not already valued + * (the exactly-once proof). The flush IS the valuation: a settled market is swept + * (deactivated, cash returned, profit materialized) and contributes 0; a live + * market is rebalanced to target and valued on its current cash. + * + * Before branching, this passively records terminal settlement from Propbook's + * exact Pyth timestamp if available: a past-expiry market is normally settled here + * and swept (contributing 0), so `current_nav` is only reached for a still-live + * market. Only in the bounded pending-settlement window (past expiry but the + * exact-expiry spot not yet inserted) does the live branch still abort through + * `current_nav`; there is no solvency-safe substitute mark for an unsettled + * expired market, and the abort clears once anyone lands the exact spot. + */ +export function valueExpiry(options: ValueExpiryOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'valuation', + 'vault', + 'market', + 'config', + 'propbookRegistry', + 'pyth', + 'bsSpot', + 'bsForward', + 'bsSvi', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'value_expiry', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface FinishFlushArguments { + valuation: RawTransactionArgument; + vault: RawTransactionArgument; + config: RawTransactionArgument; + supplyBudget: RawTransactionArgument; + withdrawBudget: RawTransactionArgument; +} +export interface FinishFlushOptions { + package?: string; + arguments: + | FinishFlushArguments + | [ + valuation: RawTransactionArgument, + vault: RawTransactionArgument, + config: RawTransactionArgument, + supplyBudget: RawTransactionArgument, + withdrawBudget: RawTransactionArgument, + ]; +} +/** + * Finish a full-pool valuation and run the LP flush: prove every snapshotted + * market was valued exactly once, price the pool NAV, then drain the + * supply/withdraw queues at that frozen mark (mint PLP for supplies, burn PLP and + * pay DUSDC for withdrawals), release the valuation lock, consume the potato, and + * return the LP-attributable pool-wide DUSDC NAV (idle + Σ active NAV, net of the + * pending-protocol-profit exclusion priced from the aggregate profit basis). + * + * `supply_budget` / `withdraw_budget` bound how many requests each queue may fill + * this flush (`None` = drain it fully); the operator sizes them to the gas left + * after valuing the snapshotted markets. The budgets are independent, so a supply + * backlog never starves withdrawals. + */ +export function finishFlush(options: FinishFlushOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + '0x1::option::Option', + '0x1::option::Option', + ] satisfies (string | null)[]; + const parameterNames = ['valuation', 'vault', 'config', 'supplyBudget', 'withdrawBudget']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'finish_flush', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface StakeDeepArguments { + vault: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + amount: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface StakeDeepOptions { + package?: string; + arguments: + | StakeDeepArguments + | [ + vault: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + amount: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Stake DEEP for trading benefits. The DEEP is held in the pool vault; the amount + * is recorded as inactive on the account and activates next epoch + * (`predict_account::active_stake_mut`, run by trade/claim flows). Callable + * anytime, any number of times. + */ +export function stakeDeep(options: StakeDeepOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, 'u64', null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = ['vault', 'wrapper', 'auth', 'config', 'amount', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'stake_deep', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface UnstakeDeepArguments { + vault: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface UnstakeDeepOptions { + package?: string; + arguments: + | UnstakeDeepArguments + | [ + vault: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** Withdraw all staked DEEP (active and inactive) at any time, no penalty. */ +export function unstakeDeep(options: UnstakeDeepOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = ['vault', 'wrapper', 'auth', 'config', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'unstake_deep', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RebalanceExpiryCashArguments { + vault: RawTransactionArgument; + market: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; +} +export interface RebalanceExpiryCashOptions { + package?: string; + arguments: + | RebalanceExpiryCashArguments + | [ + vault: RawTransactionArgument, + market: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + ]; +} +/** + * Move cash between pool idle liquidity and one expiry market. + * + * Permissionless and standalone: anyone may call it at any cadence. Handles all + * three per-market cases — initial funding of a freshly registered (unfunded) + * market, ongoing live rebalance/surplus-sweep toward target, and the + * settled-market sweep (deactivate, return all free cash, materialize profit). + * Mint asserts backing but never pulls pool cash, so this is what makes a market + * mintable. The market must already be registered to this vault + * (`registry::create_expiry_market`). Blocked while a full-pool valuation is in + * progress. + */ +export function rebalanceExpiryCash(options: RebalanceExpiryCashOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = ['vault', 'market', 'config', 'propbookRegistry', 'pyth']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'rebalance_expiry_cash', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ClaimTradingLossRebateArguments { + vault: RawTransactionArgument; + market: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface ClaimTradingLossRebateOptions { + package?: string; + arguments: + | ClaimTradingLossRebateArguments + | [ + vault: RawTransactionArgument, + market: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** Resolve the caller-owned account's settled trading-loss rebate. */ +export function claimTradingLossRebate(options: ClaimTradingLossRebateOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + null, + null, + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'vault', + 'market', + 'wrapper', + 'auth', + 'config', + 'propbookRegistry', + 'pyth', + 'root', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'claim_trading_loss_rebate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ClaimTradingLossRebatePermissionlessArguments { + vault: RawTransactionArgument; + market: RawTransactionArgument; + wrapper: RawTransactionArgument; + accountRegistry: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + pyth: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface ClaimTradingLossRebatePermissionlessOptions { + package?: string; + arguments: + | ClaimTradingLossRebatePermissionlessArguments + | [ + vault: RawTransactionArgument, + market: RawTransactionArgument, + wrapper: RawTransactionArgument, + accountRegistry: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + pyth: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Permissionlessly resolve one account's settled trading-loss rebate using Predict + * app auth. `deauthorize_app` disables this automation; owners can + * still use `claim_trading_loss_rebate` with owner auth. + */ +export function claimTradingLossRebatePermissionless( + options: ClaimTradingLossRebatePermissionlessOptions, +) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + null, + null, + null, + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'vault', + 'market', + 'wrapper', + 'accountRegistry', + 'config', + 'propbookRegistry', + 'pyth', + 'root', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'claim_trading_loss_rebate_permissionless', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SponsorFeeIncentivesArguments { + vault: RawTransactionArgument; + config: RawTransactionArgument; + payment: RawTransactionArgument; +} +export interface SponsorFeeIncentivesOptions { + package?: string; + arguments: + | SponsorFeeIncentivesArguments + | [ + vault: RawTransactionArgument, + config: RawTransactionArgument, + payment: RawTransactionArgument, + ]; +} +/** + * Sponsor taker fee incentives with DUSDC. Anyone may contribute; the payment + * joins a pool-level reserve that is excluded from PLP NAV and later allocated to + * expiry markets by the normal rebalance flow. + */ +export function sponsorFeeIncentives(options: SponsorFeeIncentivesOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null] satisfies (string | null)[]; + const parameterNames = ['vault', 'config', 'payment']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'sponsor_fee_incentives', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface LockCapitalArguments { + vault: RawTransactionArgument; + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + payment: RawTransactionArgument; +} +export interface LockCapitalOptions { + package?: string; + arguments: + | LockCapitalArguments + | [ + vault: RawTransactionArgument, + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + payment: RawTransactionArgument, + ]; +} +/** + * Bootstrap the pool exactly once: permanently lock `payment` DUSDC of minimum + * liquidity. Mints matching PLP (1:1) into the book's locked balance — never + * withdrawable, so the caller receives no shares — and joins the DUSDC into idle. + * This keeps `total_supply > 0` for the life of the pool, making the supply==0 + * bootstrap branch unreachable and the residual-idle re-bootstrap brick + * impossible. Callable only by the operator and only while the pool is pristine + * (`total_supply == 0`), so it runs exactly once; all supply/withdraw/flush flows + * abort `ENotBootstrapped` until it has. + */ +export function lockCapital(options: LockCapitalOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null] satisfies (string | null)[]; + const parameterNames = ['vault', 'config', 'AdminCap', 'payment']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'lock_capital', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RequestSupplyArguments { + vault: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + amount: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface RequestSupplyOptions { + package?: string; + arguments: + | RequestSupplyArguments + | [ + vault: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + amount: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Queue a supply request: pull `amount` DUSDC from account custody into queue + * escrow, recording the account's receive address as the fill recipient. The pull + * auto-settles any flush-delivered DUSDC first. The account receives the minted + * PLP at the next flush. Returns the queue index, the handle used to cancel before + * the flush. + */ +export function requestSupply(options: RequestSupplyOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, 'u64', null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = ['vault', 'wrapper', 'auth', 'config', 'amount', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'request_supply', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RequestWithdrawArguments { + vault: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + amount: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface RequestWithdrawOptions { + package?: string; + arguments: + | RequestWithdrawArguments + | [ + vault: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + amount: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Queue a withdraw request: pull `amount` PLP shares from account custody into + * queue escrow, recording the account's receive address as the fill recipient. The + * pull auto-settles any flush-delivered PLP first. Returns the queue index used to + * cancel before the flush. + */ +export function requestWithdraw(options: RequestWithdrawOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, 'u64', null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = ['vault', 'wrapper', 'auth', 'config', 'amount', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'request_withdraw', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CancelSupplyRequestArguments { + vault: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + index: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface CancelSupplyRequestOptions { + package?: string; + arguments: + | CancelSupplyRequestArguments + | [ + vault: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + index: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Cancel a still-pending supply request, refunding its escrowed DUSDC straight + * into the requesting account. `account` must be the request's recorded recipient. + */ +export function cancelSupplyRequest(options: CancelSupplyRequestOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, 'u64', null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = ['vault', 'wrapper', 'auth', 'config', 'index', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'cancel_supply_request', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CancelWithdrawRequestArguments { + vault: RawTransactionArgument; + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + config: RawTransactionArgument; + index: RawTransactionArgument; + root: RawTransactionArgument; +} +export interface CancelWithdrawRequestOptions { + package?: string; + arguments: + | CancelWithdrawRequestArguments + | [ + vault: RawTransactionArgument, + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + config: RawTransactionArgument, + index: RawTransactionArgument, + root: RawTransactionArgument, + ]; +} +/** + * Cancel a still-pending withdraw request, refunding its escrowed PLP straight + * into the requesting account. `account` must be the request's recorded recipient. + */ +export function cancelWithdrawRequest(options: CancelWithdrawRequestOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, null, 'u64', null, '0x2::clock::Clock'] satisfies ( + | string + | null + )[]; + const parameterNames = ['vault', 'wrapper', 'auth', 'config', 'index', 'root']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'plp', + function: 'cancel_withdraw_request', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/pool_accounting.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/pool_accounting.ts new file mode 100644 index 000000000..3f68a7f79 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/pool_accounting.ts @@ -0,0 +1,73 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Pool-owned expiry registration and cash-flow accounting. + * + * This module owns pool idle DUSDC custody, the durable set of expiries registered + * to a pool, the active expiry index used for valuation, DUSDC sent from the main + * pool into each expiry, DUSDC received back from each expiry, lifetime + * fee-incentive allocations, terminal cash watermarks, and per-expiry cap checks. + * It does not classify expiry-local liabilities or apply PLP reserve policy; + * PoolVault uses the aggregate profit basis to price PLP and decide protocol + * reserve transfers. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as balance from './deps/sui/balance.js'; +import * as table from './deps/sui/table.js'; +const $moduleName = '@local-pkg/deepbook_predict::pool_accounting'; +export const ActiveExpiry = new MoveStruct({ + name: `${$moduleName}::ActiveExpiry`, + fields: { + expiry_market_id: bcs.Address, + expiry_ms: bcs.u64(), + }, +}); +export const Ledger = new MoveStruct({ + name: `${$moduleName}::Ledger`, + fields: { + /** Idle LP-owned DUSDC available for withdrawals and expiry funding. */ + idle_balance: balance.Balance, + /** Expiry markets that still contribute active pool valuation/risk. */ + active_expiry_markets: bcs.vector(ActiveExpiry), + /** + * Permanent per-expiry accounting rows. Presence means the expiry belongs to this + * pool. + */ + registered_expiries: table.Table, + /** Pricing debit basis: DUSDC sent to expiries plus materialized terminal profit. */ + profit_basis_debits: bcs.u64(), + /** Pricing credit basis: all DUSDC received back from expiries. */ + profit_basis_credits: bcs.u64(), + /** Aggregate terminal losses that future terminal profits must recover first. */ + net_losses_to_fill: bcs.u64(), + /** + * Protocol profit already materialized into the debit basis but not yet physically + * moved to the reserve because idle was deployed in other active markets at + * materialization. Excluded from LP value until drained. + */ + pending_protocol_profit: bcs.u64(), + }, +}); +export const RegisteredExpiry = new MoveStruct({ + name: `${$moduleName}::RegisteredExpiry`, + fields: { + /** DUSDC pool allocation cap snapshotted when this expiry was created. */ + max_expiry_allocation: bcs.u64(), + /** Minimum DUSDC cash target snapshotted when this expiry was created. */ + initial_expiry_cash: bcs.u64(), + /** DUSDC sent from the main pool into this expiry. */ + sent_to_expiry: bcs.u64(), + /** DUSDC returned from this expiry to the main pool. */ + received_from_expiry: bcs.u64(), + /** Lifetime sponsor-funded fee incentives allocated to this expiry. */ + fee_incentives_allocated: bcs.u64(), + /** True once this expiry has started terminal profit/loss accounting. */ + terminal_accounting_started: bcs.bool(), + /** Received amount already consumed by terminal accounting. */ + terminal_received_watermark: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/predict_account.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/predict_account.ts new file mode 100644 index 000000000..1295c7a1a --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/predict_account.ts @@ -0,0 +1,278 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Predict's per-account state, stored as an app-data slot on a shared `Account` + * (the `account` package). + * + * This is Predict's account-local state: open positions, per-expiry trading + * summaries, DEEP stake, and sticky builder-code attribution. DUSDC/PLP/DEEP + * custody lives in `Account`. The `PredictApp` witness namespaces this slot, so + * only Predict writes it. + * + * Flow-driven state (positions, summaries, stake) is exposed through + * `public(package)` primitives that mutate Predict app data directly. User-facing + * builder-code config takes an already-loaded account, so the account package + * remains the authority boundary. + */ + +import { + MoveTuple, + MoveStruct, + normalizeMoveArguments, + type RawTransactionArgument, +} from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as table from './deps/sui/table.js'; +import * as table_1 from './deps/sui/table.js'; +const $moduleName = '@local-pkg/deepbook_predict::predict_account'; +export const PredictApp = new MoveTuple({ + name: `${$moduleName}::PredictApp`, + fields: [bcs.bool()], +}); +export const PositionKey = new MoveStruct({ + name: `${$moduleName}::PositionKey`, + fields: { + expiry_market_id: bcs.Address, + order_id: bcs.u256(), + }, +}); +export const Position = new MoveStruct({ + name: `${$moduleName}::Position`, + fields: { + /** Root order ID, carried forward unchanged across partial-close replacements. */ + root_id: bcs.u256(), + /** + * On-chain time (`clock.timestamp_ms()`) the position was opened, carried forward + * unchanged across partial-close replacements. A live redeem in the same timestamp + * is rejected, blocking an atomic mint -> oracle-update -> redeem in one + * transaction. + */ + opened_at_ms: bcs.u64(), + }, +}); +export const ExpiryTradingSummary = new MoveStruct({ + name: `${$moduleName}::ExpiryTradingSummary`, + fields: { + open_position_count: bcs.u64(), + trading_fees_paid: bcs.u64(), + gross_paid_to_expiry: bcs.u64(), + gross_received_from_expiry: bcs.u64(), + }, +}); +export const PredictData = new MoveStruct({ + name: `${$moduleName}::PredictData`, + fields: { + /** Open positions scoped by expiry market. */ + positions: table.Table, + /** Per-expiry aggregate trading cash flows and open position count. */ + expiry_summaries: table_1.Table, + /** + * DEEP staked and active for trading benefits, in raw units. Custody is pooled in + * `PoolVault`; this is this account's active share. + */ + active_stake: bcs.u64(), + /** + * DEEP staked this epoch, not yet active; rolls into `active_stake` on the first + * discount-bearing interaction in a later epoch (`active_stake_mut`). + */ + inactive_stake: bcs.u64(), + /** Epoch the active/inactive split was last reconciled in. */ + stake_epoch: bcs.u64(), + /** Sticky builder-code attribution for future trades, if set. */ + builder_code_id: bcs.option(bcs.Address), + }, +}); +export interface HasPositionArguments { + account: RawTransactionArgument; + expiryMarketId: RawTransactionArgument; + orderId: RawTransactionArgument; +} +export interface HasPositionOptions { + package?: string; + arguments: + | HasPositionArguments + | [ + account: RawTransactionArgument, + expiryMarketId: RawTransactionArgument, + orderId: RawTransactionArgument, + ]; +} +/** + * Return whether this account holds an open position for an order in one expiry + * market. + */ +export function hasPosition(options: HasPositionOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, '0x2::object::ID', 'u256'] satisfies (string | null)[]; + const parameterNames = ['account', 'expiryMarketId', 'orderId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'has_position', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ExpiryPositionCountArguments { + account: RawTransactionArgument; + expiryMarketId: RawTransactionArgument; +} +export interface ExpiryPositionCountOptions { + package?: string; + arguments: + | ExpiryPositionCountArguments + | [account: RawTransactionArgument, expiryMarketId: RawTransactionArgument]; +} +/** Return the open position row count for one expiry market. */ +export function expiryPositionCount(options: ExpiryPositionCountOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, '0x2::object::ID'] satisfies (string | null)[]; + const parameterNames = ['account', 'expiryMarketId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'expiry_position_count', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface TradingFeesPaidArguments { + account: RawTransactionArgument; + expiryMarketId: RawTransactionArgument; +} +export interface TradingFeesPaidOptions { + package?: string; + arguments: + | TradingFeesPaidArguments + | [account: RawTransactionArgument, expiryMarketId: RawTransactionArgument]; +} +/** Return aggregate pool trading fees this account paid for one expiry market. */ +export function tradingFeesPaid(options: TradingFeesPaidOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, '0x2::object::ID'] satisfies (string | null)[]; + const parameterNames = ['account', 'expiryMarketId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'trading_fees_paid', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ActiveStakeArguments { + account: RawTransactionArgument; +} +export interface ActiveStakeOptions { + package?: string; + arguments: ActiveStakeArguments | [account: RawTransactionArgument]; +} +/** Return active staked DEEP (the amount that earns benefits). */ +export function activeStake(options: ActiveStakeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['account']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'active_stake', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface InactiveStakeArguments { + account: RawTransactionArgument; +} +export interface InactiveStakeOptions { + package?: string; + arguments: InactiveStakeArguments | [account: RawTransactionArgument]; +} +/** Return inactive staked DEEP (activates next epoch). */ +export function inactiveStake(options: InactiveStakeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['account']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'inactive_stake', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BuilderCodeIdArguments { + account: RawTransactionArgument; +} +export interface BuilderCodeIdOptions { + package?: string; + arguments: BuilderCodeIdArguments | [account: RawTransactionArgument]; +} +/** Return the sticky builder-code ID, if set. */ +export function builderCodeId(options: BuilderCodeIdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['account']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'builder_code_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetBuilderCodeArguments { + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; + code: RawTransactionArgument; +} +export interface SetBuilderCodeOptions { + package?: string; + arguments: + | SetBuilderCodeArguments + | [ + wrapper: RawTransactionArgument, + auth: RawTransactionArgument, + code: RawTransactionArgument, + ]; +} +/** + * Set sticky builder-code attribution for future trades. Consumes account owner + * auth and attaches the Predict slot if the account has none. + */ +export function setBuilderCode(options: SetBuilderCodeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null] satisfies (string | null)[]; + const parameterNames = ['wrapper', 'auth', 'code']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'set_builder_code', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface UnsetBuilderCodeArguments { + wrapper: RawTransactionArgument; + auth: RawTransactionArgument; +} +export interface UnsetBuilderCodeOptions { + package?: string; + arguments: + | UnsetBuilderCodeArguments + | [wrapper: RawTransactionArgument, auth: RawTransactionArgument]; +} +/** Clear sticky builder-code attribution after consuming account owner auth. */ +export function unsetBuilderCode(options: UnsetBuilderCodeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['wrapper', 'auth']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'predict_account', + function: 'unset_builder_code', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/pricing.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/pricing.ts new file mode 100644 index 000000000..8e89369e9 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/pricing.ts @@ -0,0 +1,48 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Pricing for Predict markets. + * + * This module is the app-facing read layer for oracle data. It reads the + * standalone propbook Pyth and Block Scholes feeds on demand and computes SVI + * range prices. It does not mutate feed, pool, expiry, or position state, and it + * owns the live pricing boundary: current Propbook feed binding, pre-expiry market + * liveness, feed freshness, and Predict's pricing-safe BS input envelope. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as block_scholes_svi_feed from './deps/propbook/block_scholes_svi_feed.js'; +const $moduleName = '@local-pkg/deepbook_predict::pricing'; +export const Pricer = new MoveStruct({ + name: `${$moduleName}::Pricer`, + fields: { + /** Expiry market this snapshot was loaded for. */ + expiry_market_id: bcs.Address, + forward: bcs.u64(), + svi: block_scholes_svi_feed.SVIParams, + }, +}); +export interface ExpiryMarketIdArguments { + pricer: RawTransactionArgument; +} +export interface ExpiryMarketIdOptions { + package?: string; + arguments: ExpiryMarketIdArguments | [pricer: RawTransactionArgument]; +} +/** Return the expiry market this pricer was loaded for. */ +export function expiryMarketId(options: ExpiryMarketIdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['pricer']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pricing', + function: 'expiry_market_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/pricing_config.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/pricing_config.ts new file mode 100644 index 000000000..680805d05 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/pricing_config.ts @@ -0,0 +1,25 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Stored oracle freshness config for Predict quotes. + * + * ProtocolConfig owns this mutable policy. Pricing reads it when resolving live + * probabilities for mint and redeem flows. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::pricing_config'; +export const PricingConfig = new MoveStruct({ + name: `${$moduleName}::PricingConfig`, + fields: { + /** Maximum age for Pyth spot to be used as canonical live spot. */ + pyth_spot_freshness_ms: bcs.u64(), + /** Maximum age for Block Scholes spot and forward to be used in live pricing. */ + block_scholes_price_freshness_ms: bcs.u64(), + /** Maximum age for Block Scholes SVI params to be used in live pricing. */ + block_scholes_svi_freshness_ms: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/protocol_config.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/protocol_config.ts new file mode 100644 index 000000000..32860c9da --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/protocol_config.ts @@ -0,0 +1,674 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Protocol-wide configuration and flow gates for Predict. + * + * This shared object owns the admin-tunable config structs, the trading pause + * gate, and the transaction-local full-pool valuation lock. Flow modules decide + * which gates apply before they mutate expiry, oracle, pool, or account state. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as pricing_config from './pricing_config.js'; +import * as expiry_cash_config from './expiry_cash_config.js'; +import * as strike_exposure_config from './strike_exposure_config.js'; +import * as stake_config from './stake_config.js'; +import * as ewma_config from './ewma_config.js'; +const $moduleName = '@local-pkg/deepbook_predict::protocol_config'; +export const ProtocolConfig = new MoveStruct({ + name: `${$moduleName}::ProtocolConfig`, + fields: { + id: bcs.Address, + pricing_config: pricing_config.PricingConfig, + /** + * Merged protocol + insurance reserve share of materialized terminal profit, in + * FLOAT_SCALING. The complement accrues to LPs. + */ + protocol_reserve_profit_share: bcs.u64(), + /** Total liquidation candidates checked before mint and redeem flows. */ + trade_liquidation_budget: bcs.u64(), + expiry_cash_template_config: expiry_cash_config.ExpiryCashConfig, + strike_exposure_template_config: strike_exposure_config.StrikeExposureConfig, + stake_config: stake_config.StakeConfig, + ewma_config: ewma_config.EwmaConfig, + /** + * Minimum package version permitted to run version-gated flows. Monotonic; + * `bump_version_watermark` advances it to the running `current_version!()`, + * retiring older versions. A running version below this floor is dead + * (`assert_version`). `current_version!()` stays the upgrade-required code + * constant; this is the runtime floor. + */ + version_watermark: bcs.u64(), + /** Blocks new risk creation while true. */ + trading_paused: bcs.bool(), + /** + * Transaction-local lock held while a full-pool valuation is assembled, so no + * NAV-changing op can interleave between per-market value steps in the PTB. + */ + valuation_in_progress: bcs.bool(), + }, +}); +export interface IdArguments { + config: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [config: RawTransactionArgument]; +} +/** Return the protocol config object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['config']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface TradingPausedArguments { + config: RawTransactionArgument; +} +export interface TradingPausedOptions { + package?: string; + arguments: TradingPausedArguments | [config: RawTransactionArgument]; +} +/** Return whether trading is currently paused. */ +export function tradingPaused(options: TradingPausedOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['config']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'trading_paused', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateBaseFeeArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + fee: RawTransactionArgument; +} +export interface SetTemplateBaseFeeOptions { + package?: string; + arguments: + | SetTemplateBaseFeeArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + fee: RawTransactionArgument, + ]; +} +/** Set the base fee multiplier snapshotted by future expiry markets. */ +export function setTemplateBaseFee(options: SetTemplateBaseFeeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'fee']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_base_fee', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateMinFeeArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + fee: RawTransactionArgument; +} +export interface SetTemplateMinFeeOptions { + package?: string; + arguments: + | SetTemplateMinFeeArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + fee: RawTransactionArgument, + ]; +} +/** Set the minimum fee floor snapshotted by future expiry markets. */ +export function setTemplateMinFee(options: SetTemplateMinFeeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'fee']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_min_fee', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateExpiryFeeWindowMsArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateExpiryFeeWindowMsOptions { + package?: string; + arguments: + | SetTemplateExpiryFeeWindowMsArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the expiry-fee ramp window snapshotted by future expiry markets. */ +export function setTemplateExpiryFeeWindowMs(options: SetTemplateExpiryFeeWindowMsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_expiry_fee_window_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateExpiryFeeMaxMultiplierArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateExpiryFeeMaxMultiplierOptions { + package?: string; + arguments: + | SetTemplateExpiryFeeMaxMultiplierArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the expiry-fee max multiplier snapshotted by future expiry markets. */ +export function setTemplateExpiryFeeMaxMultiplier( + options: SetTemplateExpiryFeeMaxMultiplierOptions, +) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_expiry_fee_max_multiplier', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateLiquidationLtvArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateLiquidationLtvOptions { + package?: string; + arguments: + | SetTemplateLiquidationLtvArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the liquidation LTV snapshotted by future expiry markets. */ +export function setTemplateLiquidationLtv(options: SetTemplateLiquidationLtvOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_liquidation_ltv', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateMaxAdmissionLeverageArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateMaxAdmissionLeverageOptions { + package?: string; + arguments: + | SetTemplateMaxAdmissionLeverageArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the max admission leverage snapshotted by future expiry markets. */ +export function setTemplateMaxAdmissionLeverage(options: SetTemplateMaxAdmissionLeverageOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_max_admission_leverage', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateBackingBufferLambdaArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateBackingBufferLambdaOptions { + package?: string; + arguments: + | SetTemplateBackingBufferLambdaArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the backing-buffer lambda snapshotted by future expiry markets. */ +export function setTemplateBackingBufferLambda(options: SetTemplateBackingBufferLambdaOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_backing_buffer_lambda', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetBenefitPowersArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + lower: RawTransactionArgument; + upper: RawTransactionArgument; +} +export interface SetBenefitPowersOptions { + package?: string; + arguments: + | SetBenefitPowersArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + lower: RawTransactionArgument, + upper: RawTransactionArgument, + ]; +} +/** + * Set the staking benefit thresholds: `lower` (half of max benefits) and `upper` + * (full benefits). Validated as a pair (`upper > 2 * lower`). + */ +export function setBenefitPowers(options: SetBenefitPowersOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64', 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'lower', 'upper']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_benefit_powers', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateMinEntryProbabilityArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateMinEntryProbabilityOptions { + package?: string; + arguments: + | SetTemplateMinEntryProbabilityArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the minimum raw entry probability snapshotted by future expiry markets. */ +export function setTemplateMinEntryProbability(options: SetTemplateMinEntryProbabilityOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_min_entry_probability', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateMaxEntryProbabilityArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateMaxEntryProbabilityOptions { + package?: string; + arguments: + | SetTemplateMaxEntryProbabilityArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the maximum raw entry probability snapshotted by future expiry markets. */ +export function setTemplateMaxEntryProbability(options: SetTemplateMaxEntryProbabilityOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_max_entry_probability', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetPythSpotFreshnessMsArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetPythSpotFreshnessMsOptions { + package?: string; + arguments: + | SetPythSpotFreshnessMsArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the live Pyth spot freshness threshold. */ +export function setPythSpotFreshnessMs(options: SetPythSpotFreshnessMsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_pyth_spot_freshness_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetBlockScholesPriceFreshnessMsArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetBlockScholesPriceFreshnessMsOptions { + package?: string; + arguments: + | SetBlockScholesPriceFreshnessMsArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the live Block Scholes spot/forward freshness threshold. */ +export function setBlockScholesPriceFreshnessMs(options: SetBlockScholesPriceFreshnessMsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_block_scholes_price_freshness_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetBlockScholesSviFreshnessMsArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetBlockScholesSviFreshnessMsOptions { + package?: string; + arguments: + | SetBlockScholesSviFreshnessMsArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the live Block Scholes SVI freshness threshold. */ +export function setBlockScholesSviFreshnessMs(options: SetBlockScholesSviFreshnessMsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_block_scholes_svi_freshness_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTemplateTradingLossRebateRateArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + value: RawTransactionArgument; +} +export interface SetTemplateTradingLossRebateRateOptions { + package?: string; + arguments: + | SetTemplateTradingLossRebateRateArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + value: RawTransactionArgument, + ]; +} +/** Set the trading loss rebate rate template used by future expiry markets. */ +export function setTemplateTradingLossRebateRate(options: SetTemplateTradingLossRebateRateOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'value']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_template_trading_loss_rebate_rate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTradeLiquidationBudgetArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + budget: RawTransactionArgument; +} +export interface SetTradeLiquidationBudgetOptions { + package?: string; + arguments: + | SetTradeLiquidationBudgetArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + budget: RawTransactionArgument, + ]; +} +/** Set the total liquidation candidate budget used before mint and redeem flows. */ +export function setTradeLiquidationBudget(options: SetTradeLiquidationBudgetOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'budget']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_trade_liquidation_budget', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetEwmaParamsArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + alpha: RawTransactionArgument; + zScoreThreshold: RawTransactionArgument; + penaltyRate: RawTransactionArgument; +} +export interface SetEwmaParamsOptions { + package?: string; + arguments: + | SetEwmaParamsArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + alpha: RawTransactionArgument, + zScoreThreshold: RawTransactionArgument, + penaltyRate: RawTransactionArgument, + ]; +} +/** Set the EWMA gas-price penalty parameters. */ +export function setEwmaParams(options: SetEwmaParamsOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64', 'u64', 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'alpha', 'zScoreThreshold', 'penaltyRate']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_ewma_params', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetEwmaEnabledArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + enabled: RawTransactionArgument; +} +export interface SetEwmaEnabledOptions { + package?: string; + arguments: + | SetEwmaEnabledArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + enabled: RawTransactionArgument, + ]; +} +/** Enable or disable the EWMA gas-price penalty. */ +export function setEwmaEnabled(options: SetEwmaEnabledOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'bool'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'enabled']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_ewma_enabled', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetTradingPausedArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + paused: RawTransactionArgument; +} +export interface SetTradingPausedOptions { + package?: string; + arguments: + | SetTradingPausedArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + paused: RawTransactionArgument, + ]; +} +/** Set whether trading is paused. */ +export function setTradingPaused(options: SetTradingPausedOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'bool'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'paused']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_trading_paused', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BumpVersionWatermarkArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; +} +export interface BumpVersionWatermarkOptions { + package?: string; + arguments: + | BumpVersionWatermarkArguments + | [config: RawTransactionArgument, AdminCap: RawTransactionArgument]; +} +/** + * Advance the version watermark to this package's compiled-in + * `current_version!()`, retiring every older version (a running version below the + * floor is dead — see `assert_version`). + * + * Takes no target: the floor can only ever move to a version a published binary + * actually embeds, so admin can never set it above the running package and brick + * it. Raising the floor therefore requires executing this against the upgraded + * package, where `current_version!()` is higher. Aborts if the running version + * does not exceed the current watermark (nothing to retire). Ungated so it stays + * callable across an upgrade. + */ +export function bumpVersionWatermark(options: BumpVersionWatermarkOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'bump_version_watermark', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetProtocolReserveProfitShareArguments { + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + protocolReserveProfitShare: RawTransactionArgument; +} +export interface SetProtocolReserveProfitShareOptions { + package?: string; + arguments: + | SetProtocolReserveProfitShareArguments + | [ + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + protocolReserveProfitShare: RawTransactionArgument, + ]; +} +/** + * Set the protocol reserve profit share used when materializing aggregate expiry + * profit. Admin-gated; validated against its config-constants envelope. + */ +export function setProtocolReserveProfitShare(options: SetProtocolReserveProfitShareOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['config', 'AdminCap', 'protocolReserveProfitShare']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'protocol_config', + function: 'set_protocol_reserve_profit_share', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/registry.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/registry.ts new file mode 100644 index 000000000..b107fb3b8 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/registry.ts @@ -0,0 +1,496 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Registry and creation entrypoints for the Predict protocol. + * + * This module creates shared setup objects, owns registry-level capabilities, and + * exposes registry-owned governance/creation entrypoints. Market identity, cadence + * policy, underlying watermarks, and market uniqueness live in the embedded + * `market_manager`. Runtime pool accounting, expiry risk, oracle feeds, and user + * positions stay in their owning modules. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as market_manager from './market_manager.js'; +import * as vec_set from './deps/sui/vec_set.js'; +import * as vec_set_1 from './deps/sui/vec_set.js'; +const $moduleName = '@local-pkg/deepbook_predict::registry'; +export const Registry = new MoveStruct({ + name: `${$moduleName}::Registry`, + fields: { + id: bcs.Address, + /** + * Market identity, cadence deployment terms, underlying watermarks, and + * uniqueness. + */ + market_manager: market_manager.MarketManager, + /** + * IDs of `PauseCap` objects currently authorized to use pause-only entries. Admin + * mints into this set and revokes from it. + */ + allowed_pause_caps: vec_set.VecSet(bcs.Address), + /** + * IDs of `MarketLifecycleCap` objects currently authorized for privileged + * lifecycle entries such as market creation and full-pool valuation. Admin mints + * into this set and revokes from it. + */ + allowed_lifecycle_caps: vec_set_1.VecSet(bcs.Address), + }, +}); +export interface IdArguments { + registry: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [registry: RawTransactionArgument]; +} +/** Return the registry object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['registry']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ExpiryMarketIdArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; + expiry: RawTransactionArgument; +} +export interface ExpiryMarketIdOptions { + package?: string; + arguments: + | ExpiryMarketIdArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + expiry: RawTransactionArgument, + ]; +} +/** + * Return the expiry market ID for `(propbook_underlying_id, expiry)`, if one has + * been created. + */ +export function expiryMarketId(options: ExpiryMarketIdOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, 'u32', 'u64'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId', 'expiry']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'expiry_market_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MintPauseCapArguments { + registry: RawTransactionArgument; + AdminCap: RawTransactionArgument; +} +export interface MintPauseCapOptions { + package?: string; + arguments: + | MintPauseCapArguments + | [registry: RawTransactionArgument, AdminCap: RawTransactionArgument]; +} +/** + * Mint a new `PauseCap`. Admin-only and bypasses the version gate so the kill + * switch remains available even when admin has misconfigured versions. + */ +export function mintPauseCap(options: MintPauseCapOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['registry', 'AdminCap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'mint_pause_cap', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RevokePauseCapArguments { + registry: RawTransactionArgument; + AdminCap: RawTransactionArgument; + pauseCapId: RawTransactionArgument; +} +export interface RevokePauseCapOptions { + package?: string; + arguments: + | RevokePauseCapArguments + | [ + registry: RawTransactionArgument, + AdminCap: RawTransactionArgument, + pauseCapId: RawTransactionArgument, + ]; +} +/** Revoke a previously minted `PauseCap` by ID. Admin-only. */ +export function revokePauseCap(options: RevokePauseCapOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, '0x2::object::ID'] satisfies (string | null)[]; + const parameterNames = ['registry', 'AdminCap', 'pauseCapId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'revoke_pause_cap', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MintLifecycleCapArguments { + registry: RawTransactionArgument; + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; +} +export interface MintLifecycleCapOptions { + package?: string; + arguments: + | MintLifecycleCapArguments + | [ + registry: RawTransactionArgument, + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + ]; +} +/** + * Mint a new `MarketLifecycleCap`. Admin-only and version-gated because granting + * privileged lifecycle authority under a version freeze is risky. + */ +export function mintLifecycleCap(options: MintLifecycleCapOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null] satisfies (string | null)[]; + const parameterNames = ['registry', 'config', 'AdminCap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'mint_lifecycle_cap', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RevokeLifecycleCapArguments { + registry: RawTransactionArgument; + AdminCap: RawTransactionArgument; + lifecycleCapId: RawTransactionArgument; +} +export interface RevokeLifecycleCapOptions { + package?: string; + arguments: + | RevokeLifecycleCapArguments + | [ + registry: RawTransactionArgument, + AdminCap: RawTransactionArgument, + lifecycleCapId: RawTransactionArgument, + ]; +} +/** + * Revoke a previously minted `MarketLifecycleCap` by ID. Admin-only. Deliberately + * not version-gated (like pause-cap revocation): revocation is harm-reducing and + * must stay available even when the running package version is frozen below the + * protocol watermark. + */ +export function revokeLifecycleCap(options: RevokeLifecycleCapOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, '0x2::object::ID'] satisfies (string | null)[]; + const parameterNames = ['registry', 'AdminCap', 'lifecycleCapId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'revoke_lifecycle_cap', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface GenerateLifecycleProofArguments { + registry: RawTransactionArgument; + lifecycleCap: RawTransactionArgument; +} +export interface GenerateLifecycleProofOptions { + package?: string; + arguments: + | GenerateLifecycleProofArguments + | [registry: RawTransactionArgument, lifecycleCap: RawTransactionArgument]; +} +/** + * Generate a transaction-local proof that `lifecycle_cap` is currently + * allowlisted. Consumers take the proof by value so a revoked lifecycle cap cannot + * authorize cross-module lifecycle actions. + */ +export function generateLifecycleProof(options: GenerateLifecycleProofOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null] satisfies (string | null)[]; + const parameterNames = ['registry', 'lifecycleCap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'generate_lifecycle_proof', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PauseTradingPauseCapArguments { + config: RawTransactionArgument; + registry: RawTransactionArgument; + pauseCap: RawTransactionArgument; +} +export interface PauseTradingPauseCapOptions { + package?: string; + arguments: + | PauseTradingPauseCapArguments + | [ + config: RawTransactionArgument, + registry: RawTransactionArgument, + pauseCap: RawTransactionArgument, + ]; +} +/** Force `trading_paused = true` via a valid `PauseCap`. One-way. */ +export function pauseTradingPauseCap(options: PauseTradingPauseCapOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null] satisfies (string | null)[]; + const parameterNames = ['config', 'registry', 'pauseCap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'pause_trading_pause_cap', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PauseExpiryMarketMintPauseCapArguments { + market: RawTransactionArgument; + registry: RawTransactionArgument; + pauseCap: RawTransactionArgument; +} +export interface PauseExpiryMarketMintPauseCapOptions { + package?: string; + arguments: + | PauseExpiryMarketMintPauseCapArguments + | [ + market: RawTransactionArgument, + registry: RawTransactionArgument, + pauseCap: RawTransactionArgument, + ]; +} +/** + * Force `mint_paused = true` on a single expiry market via a valid `PauseCap`. + * One-way; admin's `expiry_market::set_mint_paused` is needed to unpause. + */ +export function pauseExpiryMarketMintPauseCap(options: PauseExpiryMarketMintPauseCapOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null] satisfies (string | null)[]; + const parameterNames = ['market', 'registry', 'pauseCap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'pause_expiry_market_mint_pause_cap', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RegisterUnderlyingArguments { + registry: RawTransactionArgument; + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface RegisterUnderlyingOptions { + package?: string; + arguments: + | RegisterUnderlyingArguments + | [ + registry: RawTransactionArgument, + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** + * Record admin approval of one Propbook underlying. Source IDs and canonical + * oracle object IDs remain owned by Propbook; this row only gates which + * underlyings Predict will build markets on and stores deployment watermarks. + */ +export function registerUnderlying(options: RegisterUnderlyingOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'config', 'AdminCap', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'register_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SetCadenceConfigArguments { + registry: RawTransactionArgument; + config: RawTransactionArgument; + AdminCap: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; + cadenceId: RawTransactionArgument; + tickSize: RawTransactionArgument; + admissionTickSize: RawTransactionArgument; + maxExpiryAllocation: RawTransactionArgument; + initialExpiryCash: RawTransactionArgument; + windowSize: RawTransactionArgument; +} +export interface SetCadenceConfigOptions { + package?: string; + arguments: + | SetCadenceConfigArguments + | [ + registry: RawTransactionArgument, + config: RawTransactionArgument, + AdminCap: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + cadenceId: RawTransactionArgument, + tickSize: RawTransactionArgument, + admissionTickSize: RawTransactionArgument, + maxExpiryAllocation: RawTransactionArgument, + initialExpiryCash: RawTransactionArgument, + windowSize: RawTransactionArgument, + ]; +} +/** + * Set all deployment terms for one underlying's cadence. Passing zero for all five + * values disables the cadence; otherwise all values must be nonzero and valid. + */ +export function setCadenceConfig(options: SetCadenceConfigOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + 'u32', + 'u8', + 'u64', + 'u64', + 'u64', + 'u64', + 'u64', + ] satisfies (string | null)[]; + const parameterNames = [ + 'registry', + 'config', + 'AdminCap', + 'propbookUnderlyingId', + 'cadenceId', + 'tickSize', + 'admissionTickSize', + 'maxExpiryAllocation', + 'initialExpiryCash', + 'windowSize', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'set_cadence_config', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CreateExpiryMarketArguments { + registry: RawTransactionArgument; + poolVault: RawTransactionArgument; + config: RawTransactionArgument; + propbookRegistry: RawTransactionArgument; + lifecycleCap: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; + cadenceId: RawTransactionArgument; +} +export interface CreateExpiryMarketOptions { + package?: string; + arguments: + | CreateExpiryMarketArguments + | [ + registry: RawTransactionArgument, + poolVault: RawTransactionArgument, + config: RawTransactionArgument, + propbookRegistry: RawTransactionArgument, + lifecycleCap: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + cadenceId: RawTransactionArgument, + ]; +} +/** + * Create the next deployable `ExpiryMarket` for one cadence on a Propbook + * underlying. + * + * Requires an allowlisted `MarketLifecycleCap`. The market manager enforces one + * market per `(propbook_underlying_id, expiry)`, that the underlying is + * admin-approved for Predict, that the cadence is enabled and inside its + * deployment window after skipping enabled higher-rank cadence slots and already + * created markets, and — via Propbook's admin-gated canonical binding — that Pyth + * spot, BS spot, and the selected expiry's BS forward/SVI feeds are bound for the + * underlying. The market snapshots the cadence tick size and admission tick size, + * while pool accounting snapshots the cadence allocation cap and initial expiry + * cash target. Priced flows resolve the canonical oracle object IDs from + * Propbook's insert-only bindings. The market is created with zero cash and + * registered with the pool vault as an accounting row only; it is not mintable + * until `plp::rebalance_expiry_cash` funds it. + */ +export function createExpiryMarket(options: CreateExpiryMarketOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [ + null, + null, + null, + null, + null, + 'u32', + 'u8', + '0x2::clock::Clock', + ] satisfies (string | null)[]; + const parameterNames = [ + 'registry', + 'poolVault', + 'config', + 'propbookRegistry', + 'lifecycleCap', + 'propbookUnderlyingId', + 'cadenceId', + ]; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'create_expiry_market', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CreateBuilderCodeArguments { + registry: RawTransactionArgument; + config: RawTransactionArgument; + index: RawTransactionArgument; +} +export interface CreateBuilderCodeOptions { + package?: string; + arguments: + | CreateBuilderCodeArguments + | [ + registry: RawTransactionArgument, + config: RawTransactionArgument, + index: RawTransactionArgument, + ]; +} +/** Create a derived shared BuilderCode for the caller and index. */ +export function createBuilderCode(options: CreateBuilderCodeOptions) { + const packageAddress = options.package ?? '@local-pkg/deepbook_predict'; + const argumentsTypes = [null, null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['registry', 'config', 'index']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'create_builder_code', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/stake_config.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/stake_config.ts new file mode 100644 index 000000000..96d97c0df --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/stake_config.ts @@ -0,0 +1,26 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Admin-tunable DEEP staking parameters and the benefit curve they drive. + * + * Benefits scale with active stake along a two-segment curve: the benefit ratio + * rises linearly from 0 to half of max over `0..lower_benefit_power`, then from + * half to full over `lower_benefit_power..upper_benefit_power`, capped at full + * above. That ratio scales the fixed `constants::max_fee_discount` for fees. The + * same benefit ratio scales settled trading-loss rebates. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::stake_config'; +export const StakeConfig = new MoveStruct({ + name: `${$moduleName}::StakeConfig`, + fields: { + /** Active stake at the curve kink (half of max benefits), in raw DEEP units. */ + lower_benefit_power: bcs.u64(), + /** Active stake for full (max) benefits, in raw DEEP units. */ + upper_benefit_power: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure.ts new file mode 100644 index 000000000..13f047581 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure.ts @@ -0,0 +1,50 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Expiry-local exposure book for one expiry market. + * + * This module interprets `Order` terms against the expiry's `tick_size`, + * recovering raw strikes from order ticks only at the pricing/settlement boundary. + * It owns the payout-liability view of the active contracts used for cash backing. + * The order floor is a static dollar amount (`floor_shares`), so order accounting + * needs no clock. It stores the parent market identity so market-scoped + * liquidation events can be emitted atomically with exposure removal. + * Expiry-market cash custody, rebate accounting, account positions, and payout + * movement stay outside this module. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as strike_exposure_config from './strike_exposure_config.js'; +import * as liquidation_book from './liquidation_book.js'; +import * as strike_payout_tree from './strike_payout_tree.js'; +const $moduleName = '@local-pkg/deepbook_predict::strike_exposure'; +export const StrikeExposure = new MoveStruct({ + name: `${$moduleName}::StrikeExposure`, + fields: { + /** Expiry market that owns this exposure book. */ + expiry_market_id: bcs.Address, + /** Terminal timestamp used by fee and settlement math. */ + expiry_ms: bcs.u64(), + /** Raw-price-per-tick conversion factor; `raw_strike = tick * tick_size`. */ + tick_size: bcs.u64(), + /** Coarser raw-price step that new finite mint boundaries must align to. */ + admission_tick_size: bcs.u64(), + /** Exact Propbook Pyth source timestamp used to derive the reference tick. */ + reference_tick_source_timestamp_ms: bcs.u64(), + /** Reference fine-grid tick that may bypass the coarser admission grid once set. */ + reference_tick: bcs.option(bcs.u64()), + /** Snapshotted exposure and fee policy for this expiry. */ + config: strike_exposure_config.StrikeExposureConfig, + next_order_sequence: bcs.u64(), + /** Remaining settled liability after settlement has been materialized. */ + settled_payout_liability: bcs.u64(), + /** True once `settled_payout_liability` has been materialized. */ + settled_liability_materialized: bcs.bool(), + liquidation: liquidation_book.LiquidationBook, + /** Sparse payout tree for live cash backing and settled liability. */ + payout: strike_payout_tree.StrikePayoutTree, + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure_config.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure_config.ts new file mode 100644 index 000000000..9ad0728ff --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/strike_exposure_config.ts @@ -0,0 +1,54 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Stored strike-exposure policy config. + * + * ProtocolConfig owns the current global template. Each StrikeExposure stores a + * snapshot initialized from that template, so later admin updates do not reprice + * active markets. Fee policy lives here because fees consume prices but are not + * themselves contract probability. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::strike_exposure_config'; +export const StrikeExposureConfig = new MoveStruct({ + name: `${$moduleName}::StrikeExposureConfig`, + fields: { + /** + * 1e9-scaled floor-to-live-value threshold for liquidation. `850_000_000` means + * liquidate at 85% LTV. With a static floor the trigger is + * `qty·P <= floor_shares / liquidation_ltv`; the buffer is the anti-arbitrage + * enforcement margin (knock out a hair before zero equity), not a solvency margin + * — the reserve already backs the full `Q - F`. + */ + liquidation_ltv: bcs.u64(), + /** + * Global max leverage for mint admission, before the low-probability curve scales + * it down. Actual liquidation still uses `liquidation_ltv`. + */ + max_admission_leverage: bcs.u64(), + /** + * Fraction of the disjoint-book backing gap reserved for early exits. 1.0 fully + * reserves early exits, matching the pre-buffer summed reserve. + */ + backing_buffer_lambda: bcs.u64(), + /** + * Base fee multiplier for Bernoulli scaling. Effective base fee = base_fee _ + * sqrt(price _ (1 - price)). + */ + base_fee: bcs.u64(), + /** Minimum per-unit fee floor; live trade fees never go below this value. */ + min_fee: bcs.u64(), + /** Minimum raw entry probability allowed for mint admission. */ + min_entry_probability: bcs.u64(), + /** Maximum raw entry probability allowed for mint admission. */ + max_entry_probability: bcs.u64(), + /** Window before expiry over which trade fees ramp up. */ + expiry_fee_window_ms: bcs.u64(), + /** Fee multiplier reached at expiry, in FLOAT_SCALING; 1x disables the ramp. */ + expiry_fee_max_multiplier: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/strike_payout_tree.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/strike_payout_tree.ts new file mode 100644 index 000000000..b407f1000 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/strike_payout_tree.ts @@ -0,0 +1,81 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Sparse strike exposure index for payout-liability accounting. + * + * The tree keys finite interval boundaries by absolute tick, matching the tick + * pair packed into the durable order ID. Raw strikes are recovered only at the + * pricing/settlement boundary, where callers pass the owning market's `tick_size` + * (`raw_strike = tick * tick_size`); the tree stores no grid geometry. + * + * This treap stores finite interval boundaries touched by positions. It tracks + * each order's quantity and static floor shares, deriving net payout + * (`quantity - floor_shares = Q - F`) for settled liability and max single-point + * payout. Live cash backing is the max-point net payout plus a buffer over the + * disjoint-book gap; the tree's max-point term is the floor anchor of that + * enforced reserve. + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import * as table from './deps/sui/table.js'; +const $moduleName = '@local-pkg/deepbook_predict::strike_payout_tree'; +export const PayoutTerms = new MoveStruct({ + name: `${$moduleName}::PayoutTerms`, + fields: { + /** + * Aggregate order quantity over the prefix. Read by the NAV linear walk + * (`walk_linear`), which prices each boundary's start/end quantity. + */ + quantity: bcs.u64(), + /** + * Aggregate static floor shares over the prefix. Net payout is derived as + * `quantity - floor_shares` for settled liability and max-point reserve reads. + */ + floor_shares: bcs.u64(), + }, +}); +export const StrikePayoutTree = new MoveStruct({ + name: `${$moduleName}::StrikePayoutTree`, + fields: { + root: bcs.option(bcs.u64()), + nodes: table.Table, + node_count: bcs.u64(), + base: PayoutTerms, + }, +}); +export const PayoutSummary = new MoveStruct({ + name: `${$moduleName}::PayoutSummary`, + fields: { + total_start: PayoutTerms, + total_end: PayoutTerms, + max_net_payout_prefix_gain: bcs.u64(), + /** + * Exact tick span of this subtree (BST invariant: leftmost / rightmost node key). + * `up_price` is monotone decreasing in strike, so + * `[up_price(max_tick·ts), up_price(min_tick·ts)]` bounds every node price in the + * subtree — the basis for `walk_linear`'s bounded interpolation. Set in `new_leaf` + * / `resummarize`; the `combine_summaries` / `zero_summary` outputs leave these + * `0` (the owning node overwrites them). + */ + min_tick: bcs.u64(), + max_tick: bcs.u64(), + }, +}); +export const PayoutNode = new MoveStruct({ + name: `${$moduleName}::PayoutNode`, + fields: { + priority: bcs.u64(), + left: bcs.option(bcs.u64()), + right: bcs.option(bcs.u64()), + /** + * This node's own boundary terms, stored so the subtree `summary` can be + * recomputed without deriving locals by subtracting child summaries. + */ + local_start: PayoutTerms, + local_end: PayoutTerms, + summary: PayoutSummary, + }, +}); diff --git a/packages/deepbook-predict/src/contracts/deepbook_predict/vault_events.ts b/packages/deepbook-predict/src/contracts/deepbook_predict/vault_events.ts new file mode 100644 index 000000000..97d9b7ad9 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/deepbook_predict/vault_events.ts @@ -0,0 +1,189 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Pool-vault events for Predict: DEEP staking, expiry cash/profit, fee incentives, + * and the async LP supply/withdraw request → flush lifecycle (the flush event + * carries the full-pool valuation it priced fills at). + */ + +import { MoveStruct } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '@local-pkg/deepbook_predict::vault_events'; +export const ExpiryCashReceived = new MoveStruct({ + name: `${$moduleName}::ExpiryCashReceived`, + fields: { + pool_vault_id: bcs.Address, + expiry_market_id: bcs.Address, + settlement_price: bcs.u64(), + amount: bcs.u64(), + }, +}); +export const ExpiryCashRebalanced = new MoveStruct({ + name: `${$moduleName}::ExpiryCashRebalanced`, + fields: { + pool_vault_id: bcs.Address, + expiry_market_id: bcs.Address, + amount: bcs.u64(), + to_expiry: bcs.bool(), + target_cash: bcs.u64(), + protocol_profit_realized: bcs.u64(), + }, +}); +export const ExpiryProfitMaterialized = new MoveStruct({ + name: `${$moduleName}::ExpiryProfitMaterialized`, + fields: { + pool_vault_id: bcs.Address, + expiry_market_id: bcs.Address, + lp_profit: bcs.u64(), + protocol_profit: bcs.u64(), + protocol_reserve_balance_after: bcs.u64(), + profit_basis_after: bcs.u64(), + pending_protocol_profit_after: bcs.u64(), + }, +}); +export const TradingLossRebateClaimed = new MoveStruct({ + name: `${$moduleName}::TradingLossRebateClaimed`, + fields: { + pool_vault_id: bcs.Address, + expiry_market_id: bcs.Address, + account_id: bcs.Address, + rebate_amount: bcs.u64(), + residual_returned: bcs.u64(), + }, +}); +export const DeepStaked = new MoveStruct({ + name: `${$moduleName}::DeepStaked`, + fields: { + pool_vault_id: bcs.Address, + account_id: bcs.Address, + amount: bcs.u64(), + /** + * Account active/inactive stake after the deposit. Freshly staked DEEP is inactive + * until it rolls active in a later epoch, so both are reported. + */ + active_stake_after: bcs.u64(), + inactive_stake_after: bcs.u64(), + }, +}); +export const DeepUnstaked = new MoveStruct({ + name: `${$moduleName}::DeepUnstaked`, + fields: { + pool_vault_id: bcs.Address, + account_id: bcs.Address, + amount: bcs.u64(), + }, +}); +export const SupplyRequested = new MoveStruct({ + name: `${$moduleName}::SupplyRequested`, + fields: { + pool_vault_id: bcs.Address, + account_id: bcs.Address, + recipient: bcs.Address, + index: bcs.u64(), + amount: bcs.u64(), + }, +}); +export const WithdrawRequested = new MoveStruct({ + name: `${$moduleName}::WithdrawRequested`, + fields: { + pool_vault_id: bcs.Address, + account_id: bcs.Address, + recipient: bcs.Address, + index: bcs.u64(), + amount: bcs.u64(), + }, +}); +export const RequestCancelled = new MoveStruct({ + name: `${$moduleName}::RequestCancelled`, + fields: { + pool_vault_id: bcs.Address, + account_id: bcs.Address, + recipient: bcs.Address, + index: bcs.u64(), + amount: bcs.u64(), + is_supply: bcs.bool(), + }, +}); +export const SupplyFilled = new MoveStruct({ + name: `${$moduleName}::SupplyFilled`, + fields: { + pool_vault_id: bcs.Address, + account_id: bcs.Address, + recipient: bcs.Address, + index: bcs.u64(), + dusdc_amount: bcs.u64(), + shares_minted: bcs.u64(), + }, +}); +export const WithdrawFilled = new MoveStruct({ + name: `${$moduleName}::WithdrawFilled`, + fields: { + pool_vault_id: bcs.Address, + account_id: bcs.Address, + recipient: bcs.Address, + index: bcs.u64(), + shares_burned: bcs.u64(), + dusdc_amount: bcs.u64(), + }, +}); +export const FlushExecuted = new MoveStruct({ + name: `${$moduleName}::FlushExecuted`, + fields: { + pool_vault_id: bcs.Address, + epoch: bcs.u64(), + /** + * LP-attributable pool NAV every fill was priced at: idle plus + * `active_market_nav`, excluding unrealized and pending protocol profit. + */ + pool_value: bcs.u64(), + total_supply: bcs.u64(), + /** Σ of each active market's exact NAV at valuation (settled markets contribute 0). */ + active_market_nav: bcs.u64(), + /** Number of active markets valued for this flush. */ + market_count: bcs.u64(), + /** Idle DUSDC held by the pool at valuation time, before the drain. */ + idle_balance_before: bcs.u64(), + supplies_filled: bcs.u64(), + withdrawals_filled: bcs.u64(), + requests_processed: bcs.u64(), + idle_balance_after: bcs.u64(), + }, +}); +export const CapitalLocked = new MoveStruct({ + name: `${$moduleName}::CapitalLocked`, + fields: { + pool_vault_id: bcs.Address, + amount: bcs.u64(), + }, +}); +export const FeeIncentivesSponsored = new MoveStruct({ + name: `${$moduleName}::FeeIncentivesSponsored`, + fields: { + pool_vault_id: bcs.Address, + sponsor: bcs.Address, + amount: bcs.u64(), + reserve_after: bcs.u64(), + }, +}); +export const FeeIncentivesAllocated = new MoveStruct({ + name: `${$moduleName}::FeeIncentivesAllocated`, + fields: { + pool_vault_id: bcs.Address, + expiry_market_id: bcs.Address, + amount: bcs.u64(), + pool_reserve_after: bcs.u64(), + expiry_incentive_balance_after: bcs.u64(), + expiry_incentives_allocated_after: bcs.u64(), + }, +}); +export const FeeIncentivesReturned = new MoveStruct({ + name: `${$moduleName}::FeeIncentivesReturned`, + fields: { + pool_vault_id: bcs.Address, + expiry_market_id: bcs.Address, + amount: bcs.u64(), + pool_reserve_after: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/propbook/block_scholes_forward_feed.ts b/packages/deepbook-predict/src/contracts/propbook/block_scholes_forward_feed.ts new file mode 100644 index 000000000..e6cd2fd8d --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/block_scholes_forward_feed.ts @@ -0,0 +1,332 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Block Scholes forward oracle: one shared object per source id, storing + * per-expiry forward streams keyed by expiry timestamp. + * + * Predict-unaware: this module stores raw source facts and leaves feed binding, + * freshness, and pricing-safe envelopes to consumers. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as table from './deps/sui/table.js'; +const $moduleName = '@local-pkg/propbook::block_scholes_forward_feed'; +export const RawForward = new MoveStruct({ + name: `${$moduleName}::RawForward`, + fields: { + bs_source_id: bcs.u32(), + expiry_ms: bcs.u64(), + forward: bcs.u64(), + }, +}); +export const BlockScholesForwardFeed = new MoveStruct({ + name: `${$moduleName}::BlockScholesForwardFeed`, + fields: { + id: bcs.Address, + bs_source_id: bcs.u32(), + /** + * Package version this feed runs at; updates require an exact match and `migrate` + * advances it forward-only after a package upgrade. + */ + version: bcs.u64(), + expiries: table.Table, + }, +}); +export interface IdArguments { + feed: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [feed: RawTransactionArgument]; +} +/** Return the feed object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BsSourceIdArguments { + feed: RawTransactionArgument; +} +export interface BsSourceIdOptions { + package?: string; + arguments: BsSourceIdArguments | [feed: RawTransactionArgument]; +} +/** Return the Block Scholes source id this feed is bound to. */ +export function bsSourceId(options: BsSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'bs_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface VersionArguments { + feed: RawTransactionArgument; +} +export interface VersionOptions { + package?: string; + arguments: VersionArguments | [feed: RawTransactionArgument]; +} +/** Return the package version this feed runs at. */ +export function version(options: VersionOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'version', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawForwardArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; +} +export interface RawForwardOptions { + package?: string; + arguments: + | RawForwardArguments + | [feed: RawTransactionArgument, expiryMs: RawTransactionArgument]; +} +/** Latest raw BS forward read for `expiry_ms`. Aborts if no live update has landed. */ +export function rawForward(options: RawForwardOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'raw_forward', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedForwardArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; +} +export interface NormalizedForwardOptions { + package?: string; + arguments: + | NormalizedForwardArguments + | [feed: RawTransactionArgument, expiryMs: RawTransactionArgument]; +} +/** Latest Propbook-normalized forward in 1e9 price scaling for `expiry_ms`. */ +export function normalizedForward(options: NormalizedForwardOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'normalized_forward', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawForwardAtArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface RawForwardAtOptions { + package?: string; + arguments: + | RawForwardAtArguments + | [ + feed: RawTransactionArgument, + expiryMs: RawTransactionArgument, + timestampMs: RawTransactionArgument, + ]; +} +/** Exact raw BS forward read for `(expiry_ms, timestamp_ms)`. */ +export function rawForwardAt(options: RawForwardAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64', 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'raw_forward_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedForwardAtArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface NormalizedForwardAtOptions { + package?: string; + arguments: + | NormalizedForwardAtArguments + | [ + feed: RawTransactionArgument, + expiryMs: RawTransactionArgument, + timestampMs: RawTransactionArgument, + ]; +} +/** + * Exact Propbook-normalized forward in 1e9 price scaling for + * `(expiry_ms, timestamp_ms)`. + */ +export function normalizedForwardAt(options: NormalizedForwardAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64', 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'normalized_forward_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawBsSourceIdArguments { + raw: RawTransactionArgument; +} +export interface RawBsSourceIdOptions { + package?: string; + arguments: RawBsSourceIdArguments | [raw: RawTransactionArgument]; +} +export function rawBsSourceId(options: RawBsSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'raw_bs_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawExpiryMsArguments { + raw: RawTransactionArgument; +} +export interface RawExpiryMsOptions { + package?: string; + arguments: RawExpiryMsArguments | [raw: RawTransactionArgument]; +} +export function rawExpiryMs(options: RawExpiryMsOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'raw_expiry_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawForwardValueArguments { + raw: RawTransactionArgument; +} +export interface RawForwardValueOptions { + package?: string; + arguments: RawForwardValueArguments | [raw: RawTransactionArgument]; +} +export function rawForwardValue(options: RawForwardValueOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'raw_forward_value', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface UpdateArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface UpdateOptions { + package?: string; + arguments: + | UpdateArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** Ingest a verified BS forward update into this feed's generic oracle lane. */ +export function update(options: UpdateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'update', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface InsertAtArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface InsertAtOptions { + package?: string; + arguments: + | InsertAtArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** + * Insert an exact BS forward observation keyed by the update-derived source + * timestamp. This does not mutate the live latest observation. + */ +export function insertAt(options: InsertAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'insert_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MigrateArguments { + feed: RawTransactionArgument; +} +export interface MigrateOptions { + package?: string; + arguments: MigrateArguments | [feed: RawTransactionArgument]; +} +/** + * Migrate this feed to the running package version. Forward-only: + * `current_version!()` is compiled into each package version's bytecode. + */ +export function migrate(options: MigrateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_forward_feed', + function: 'migrate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/propbook/block_scholes_spot_feed.ts b/packages/deepbook-predict/src/contracts/propbook/block_scholes_spot_feed.ts new file mode 100644 index 000000000..f7fefabd8 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/block_scholes_spot_feed.ts @@ -0,0 +1,294 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Block Scholes spot oracle: one shared object per source id, storing the + * source-native spot stream through a generic Propbook oracle lane. + * + * The verified `SpotUpdate` is its own provenance proof. Predict-unaware: this + * module stores raw source facts and leaves feed binding, freshness, and + * pricing-safe envelopes to consumers. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as oracle_lane from './oracle_lane.js'; +const $moduleName = '@local-pkg/propbook::block_scholes_spot_feed'; +export const RawSpot = new MoveStruct({ + name: `${$moduleName}::RawSpot`, + fields: { + bs_source_id: bcs.u32(), + spot: bcs.u64(), + }, +}); +export const BlockScholesSpotFeed = new MoveStruct({ + name: `${$moduleName}::BlockScholesSpotFeed`, + fields: { + id: bcs.Address, + bs_source_id: bcs.u32(), + /** + * Package version this feed runs at; updates require an exact match and `migrate` + * advances it forward-only after a package upgrade. + */ + version: bcs.u64(), + lane: oracle_lane.OracleLane(RawSpot), + }, +}); +export interface IdArguments { + feed: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [feed: RawTransactionArgument]; +} +/** Return the feed object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BsSourceIdArguments { + feed: RawTransactionArgument; +} +export interface BsSourceIdOptions { + package?: string; + arguments: BsSourceIdArguments | [feed: RawTransactionArgument]; +} +/** Return the Block Scholes source id this feed is bound to. */ +export function bsSourceId(options: BsSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'bs_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface VersionArguments { + feed: RawTransactionArgument; +} +export interface VersionOptions { + package?: string; + arguments: VersionArguments | [feed: RawTransactionArgument]; +} +/** Return the package version this feed runs at. */ +export function version(options: VersionOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'version', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSpotArguments { + feed: RawTransactionArgument; +} +export interface RawSpotOptions { + package?: string; + arguments: RawSpotArguments | [feed: RawTransactionArgument]; +} +/** Latest raw BS spot read. Aborts if no live update has landed. */ +export function rawSpot(options: RawSpotOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'raw_spot', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedSpotArguments { + feed: RawTransactionArgument; +} +export interface NormalizedSpotOptions { + package?: string; + arguments: NormalizedSpotArguments | [feed: RawTransactionArgument]; +} +/** Latest Propbook-normalized spot in 1e9 price scaling. */ +export function normalizedSpot(options: NormalizedSpotOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'normalized_spot', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSpotAtArguments { + feed: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface RawSpotAtOptions { + package?: string; + arguments: + | RawSpotAtArguments + | [feed: RawTransactionArgument, timestampMs: RawTransactionArgument]; +} +/** Exact raw BS spot read for `timestamp_ms`. */ +export function rawSpotAt(options: RawSpotAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'raw_spot_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedSpotAtArguments { + feed: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface NormalizedSpotAtOptions { + package?: string; + arguments: + | NormalizedSpotAtArguments + | [feed: RawTransactionArgument, timestampMs: RawTransactionArgument]; +} +/** Exact Propbook-normalized spot in 1e9 price scaling for `timestamp_ms`. */ +export function normalizedSpotAt(options: NormalizedSpotAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'normalized_spot_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawBsSourceIdArguments { + raw: RawTransactionArgument; +} +export interface RawBsSourceIdOptions { + package?: string; + arguments: RawBsSourceIdArguments | [raw: RawTransactionArgument]; +} +export function rawBsSourceId(options: RawBsSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'raw_bs_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSpotValueArguments { + raw: RawTransactionArgument; +} +export interface RawSpotValueOptions { + package?: string; + arguments: RawSpotValueArguments | [raw: RawTransactionArgument]; +} +export function rawSpotValue(options: RawSpotValueOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'raw_spot_value', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface UpdateArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface UpdateOptions { + package?: string; + arguments: + | UpdateArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** Ingest a verified BS spot update into this feed's generic oracle lane. */ +export function update(options: UpdateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'update', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface InsertAtArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface InsertAtOptions { + package?: string; + arguments: + | InsertAtArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** + * Insert an exact BS spot observation keyed by the update-derived source + * timestamp. This does not mutate the live latest observation. + */ +export function insertAt(options: InsertAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'insert_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MigrateArguments { + feed: RawTransactionArgument; +} +export interface MigrateOptions { + package?: string; + arguments: MigrateArguments | [feed: RawTransactionArgument]; +} +/** + * Migrate this feed to the running package version. Forward-only: + * `current_version!()` is compiled into each package version's bytecode. + */ +export function migrate(options: MigrateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_spot_feed', + function: 'migrate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/propbook/block_scholes_svi_feed.ts b/packages/deepbook-predict/src/contracts/propbook/block_scholes_svi_feed.ts new file mode 100644 index 000000000..b5e837d91 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/block_scholes_svi_feed.ts @@ -0,0 +1,436 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Block Scholes SVI oracle: one shared object per source id, storing per-expiry + * volatility-surface streams keyed by expiry timestamp. + * + * Propbook does not validate Predict's pricing-safe SVI envelope; consumers own + * any bounds or no-arbitrage policy needed by their pricing math. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as i64 from './deps/fixed_math/i64.js'; +import * as i64_1 from './deps/fixed_math/i64.js'; +import * as table from './deps/sui/table.js'; +const $moduleName = '@local-pkg/propbook::block_scholes_svi_feed'; +export const SVIParams = new MoveStruct({ + name: `${$moduleName}::SVIParams`, + fields: { + a: bcs.u64(), + b: bcs.u64(), + rho: i64.I64, + m: i64_1.I64, + sigma: bcs.u64(), + }, +}); +export const RawSVI = new MoveStruct({ + name: `${$moduleName}::RawSVI`, + fields: { + bs_source_id: bcs.u32(), + expiry_ms: bcs.u64(), + svi: SVIParams, + }, +}); +export const BlockScholesSVIFeed = new MoveStruct({ + name: `${$moduleName}::BlockScholesSVIFeed`, + fields: { + id: bcs.Address, + bs_source_id: bcs.u32(), + /** + * Package version this feed runs at; updates require an exact match and `migrate` + * advances it forward-only after a package upgrade. + */ + version: bcs.u64(), + expiries: table.Table, + }, +}); +export interface IdArguments { + feed: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [feed: RawTransactionArgument]; +} +/** Return the feed object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BsSourceIdArguments { + feed: RawTransactionArgument; +} +export interface BsSourceIdOptions { + package?: string; + arguments: BsSourceIdArguments | [feed: RawTransactionArgument]; +} +/** Return the Block Scholes source id this feed is bound to. */ +export function bsSourceId(options: BsSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'bs_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface VersionArguments { + feed: RawTransactionArgument; +} +export interface VersionOptions { + package?: string; + arguments: VersionArguments | [feed: RawTransactionArgument]; +} +/** Return the package version this feed runs at. */ +export function version(options: VersionOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'version', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSviArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; +} +export interface RawSviOptions { + package?: string; + arguments: + | RawSviArguments + | [feed: RawTransactionArgument, expiryMs: RawTransactionArgument]; +} +/** Latest raw BS SVI read for `expiry_ms`. Aborts if no live update has landed. */ +export function rawSvi(options: RawSviOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'raw_svi', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedSviArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; +} +export interface NormalizedSviOptions { + package?: string; + arguments: + | NormalizedSviArguments + | [feed: RawTransactionArgument, expiryMs: RawTransactionArgument]; +} +/** Latest Propbook-normalized SVI params for `expiry_ms`. */ +export function normalizedSvi(options: NormalizedSviOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'normalized_svi', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSviAtArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface RawSviAtOptions { + package?: string; + arguments: + | RawSviAtArguments + | [ + feed: RawTransactionArgument, + expiryMs: RawTransactionArgument, + timestampMs: RawTransactionArgument, + ]; +} +/** Exact raw BS SVI read for `(expiry_ms, timestamp_ms)`. */ +export function rawSviAt(options: RawSviAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64', 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'raw_svi_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedSviAtArguments { + feed: RawTransactionArgument; + expiryMs: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface NormalizedSviAtOptions { + package?: string; + arguments: + | NormalizedSviAtArguments + | [ + feed: RawTransactionArgument, + expiryMs: RawTransactionArgument, + timestampMs: RawTransactionArgument, + ]; +} +/** Exact Propbook-normalized SVI params for `(expiry_ms, timestamp_ms)`. */ +export function normalizedSviAt(options: NormalizedSviAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64', 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'expiryMs', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'normalized_svi_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawBsSourceIdArguments { + raw: RawTransactionArgument; +} +export interface RawBsSourceIdOptions { + package?: string; + arguments: RawBsSourceIdArguments | [raw: RawTransactionArgument]; +} +export function rawBsSourceId(options: RawBsSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'raw_bs_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawExpiryMsArguments { + raw: RawTransactionArgument; +} +export interface RawExpiryMsOptions { + package?: string; + arguments: RawExpiryMsArguments | [raw: RawTransactionArgument]; +} +export function rawExpiryMs(options: RawExpiryMsOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'raw_expiry_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSviParamsArguments { + raw: RawTransactionArgument; +} +export interface RawSviParamsOptions { + package?: string; + arguments: RawSviParamsArguments | [raw: RawTransactionArgument]; +} +export function rawSviParams(options: RawSviParamsOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'raw_svi_params', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface AArguments { + params: RawTransactionArgument; +} +export interface AOptions { + package?: string; + arguments: AArguments | [params: RawTransactionArgument]; +} +export function a(options: AOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['params']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'a', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BArguments { + params: RawTransactionArgument; +} +export interface BOptions { + package?: string; + arguments: BArguments | [params: RawTransactionArgument]; +} +export function b(options: BOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['params']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'b', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RhoArguments { + params: RawTransactionArgument; +} +export interface RhoOptions { + package?: string; + arguments: RhoArguments | [params: RawTransactionArgument]; +} +export function rho(options: RhoOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['params']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'rho', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MArguments { + params: RawTransactionArgument; +} +export interface MOptions { + package?: string; + arguments: MArguments | [params: RawTransactionArgument]; +} +export function m(options: MOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['params']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'm', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SigmaArguments { + params: RawTransactionArgument; +} +export interface SigmaOptions { + package?: string; + arguments: SigmaArguments | [params: RawTransactionArgument]; +} +export function sigma(options: SigmaOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['params']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'sigma', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface UpdateArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface UpdateOptions { + package?: string; + arguments: + | UpdateArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** Ingest a verified BS SVI update into this feed's generic oracle lane. */ +export function update(options: UpdateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'update', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface InsertAtArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface InsertAtOptions { + package?: string; + arguments: + | InsertAtArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** + * Insert an exact BS SVI observation keyed by the update-derived source timestamp. + * This does not mutate the live latest observation. + */ +export function insertAt(options: InsertAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'insert_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MigrateArguments { + feed: RawTransactionArgument; +} +export interface MigrateOptions { + package?: string; + arguments: MigrateArguments | [feed: RawTransactionArgument]; +} +/** + * Migrate this feed to the running package version. Forward-only: + * `current_version!()` is compiled into each package version's bytecode. + */ +export function migrate(options: MigrateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'block_scholes_svi_feed', + function: 'migrate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/propbook/deps/fixed_math/i64.ts b/packages/deepbook-predict/src/contracts/propbook/deps/fixed_math/i64.ts new file mode 100644 index 000000000..ed1c669a4 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/deps/fixed_math/i64.ts @@ -0,0 +1,16 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** Signed u64 magnitude with normalized zero. */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = 'fixed_math::i64'; +export const I64 = new MoveStruct({ + name: `${$moduleName}::I64`, + fields: { + magnitude: bcs.u64(), + is_negative: bcs.bool(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/propbook/deps/sui/table.ts b/packages/deepbook-predict/src/contracts/propbook/deps/sui/table.ts new file mode 100644 index 000000000..41e18b1d1 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/deps/sui/table.ts @@ -0,0 +1,36 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * A table is a map-like collection. But unlike a traditional collection, it's keys + * and values are not stored within the `Table` value, but instead are stored using + * Sui's object system. The `Table` struct acts only as a handle into the object + * system to retrieve those keys and values. Note that this means that `Table` + * values with exactly the same key-value mapping will not be equal, with `==`, at + * runtime. For example + * + * ``` + * let table1 = table::new(); + * let table2 = table::new(); + * table::add(&mut table1, 0, false); + * table::add(&mut table1, 1, true); + * table::add(&mut table2, 0, false); + * table::add(&mut table2, 1, true); + * // table1 does not equal table2, despite having the same entries + * assert!(&table1 != &table2); + * ``` + */ + +import { MoveStruct } from '../../../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +const $moduleName = '0x2::table'; +export const Table = new MoveStruct({ + name: `${$moduleName}::Table`, + fields: { + /** the ID of this table */ + id: bcs.Address, + /** the number of key-value pairs in the table */ + size: bcs.u64(), + }, +}); diff --git a/packages/deepbook-predict/src/contracts/propbook/oracle_lane.ts b/packages/deepbook-predict/src/contracts/propbook/oracle_lane.ts new file mode 100644 index 000000000..4e135b459 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/oracle_lane.ts @@ -0,0 +1,137 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Generic Propbook oracle lane. A lane is one advancing source stream with: + * + * - one latest source observation, + * - insert-only exact timestamp history, and + * - the normal latest / exact insertion events. + * + * `source_timestamp_ms` is Propbook's canonical freshness key. Source modules may + * keep richer native timestamps inside `Payload`, but lane ordering, exact-history + * keys, and future-source checks are all millisecond-denominated; lane writes that + * are future, zero, stale, or duplicate are no-ops. + */ + +import { type BcsType, bcs } from '@mysten/sui/bcs'; +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as table from './deps/sui/table.js'; +const $moduleName = '@local-pkg/propbook::oracle_lane'; +/** + * Timestamped oracle read. Raw and normalized reads use the same timestamp + * envelope, so consumers can apply one freshness policy regardless of which + * projection they read. + */ +export function OracleRead>(...typeParameters: [Value]) { + return new MoveStruct({ + name: `${$moduleName}::OracleRead<${typeParameters[0].name as Value['name']}>`, + fields: { + source_timestamp_ms: bcs.u64(), + update_timestamp_ms: bcs.u64(), + value: typeParameters[0], + }, + }); +} +/** One advancing oracle lane. */ +export function OracleLane>(...typeParameters: [Payload]) { + return new MoveStruct({ + name: `${$moduleName}::OracleLane<${typeParameters[0].name as Payload['name']}>`, + fields: { + latest: bcs.option(OracleRead(typeParameters[0])), + exact_reads: table.Table, + }, + }); +} +/** + * Emitted when a feed accepts a source-native observation into its live oracle + * state. + */ +export function ObservationRecorded>( + ...typeParameters: [Observation] +) { + return new MoveStruct({ + name: `${$moduleName}::ObservationRecorded<${typeParameters[0].name as Observation['name']}>`, + fields: { + propbook_oracle_id: bcs.Address, + observation: typeParameters[0], + }, + }); +} +/** Emitted when a feed inserts source-native data keyed by exact source timestamp. */ +export function ObservationInserted>( + ...typeParameters: [Observation] +) { + return new MoveStruct({ + name: `${$moduleName}::ObservationInserted<${typeParameters[0].name as Observation['name']}>`, + fields: { + propbook_oracle_id: bcs.Address, + observation: typeParameters[0], + }, + }); +} +export interface ReadSourceTimestampMsArguments { + read: RawTransactionArgument; +} +export interface ReadSourceTimestampMsOptions { + package?: string; + arguments: ReadSourceTimestampMsArguments | [read: RawTransactionArgument]; + typeArguments: [string]; +} +export function readSourceTimestampMs(options: ReadSourceTimestampMsOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['read']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'oracle_lane', + function: 'read_source_timestamp_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface ReadUpdateTimestampMsArguments { + read: RawTransactionArgument; +} +export interface ReadUpdateTimestampMsOptions { + package?: string; + arguments: ReadUpdateTimestampMsArguments | [read: RawTransactionArgument]; + typeArguments: [string]; +} +export function readUpdateTimestampMs(options: ReadUpdateTimestampMsOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['read']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'oracle_lane', + function: 'read_update_timestamp_ms', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} +export interface ReadValueArguments { + read: RawTransactionArgument; +} +export interface ReadValueOptions { + package?: string; + arguments: ReadValueArguments | [read: RawTransactionArgument]; + typeArguments: [string]; +} +export function readValue(options: ReadValueOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['read']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'oracle_lane', + function: 'read_value', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + typeArguments: options.typeArguments, + }); +} diff --git a/packages/deepbook-predict/src/contracts/propbook/pyth_feed.ts b/packages/deepbook-predict/src/contracts/propbook/pyth_feed.ts new file mode 100644 index 000000000..a8fb0c5b3 --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/pyth_feed.ts @@ -0,0 +1,382 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Pyth Lazer spot oracle. It decodes verified Lazer updates into source-native + * payloads, then stores them through a generic Propbook oracle lane. Feed + * uniqueness per Pyth Lazer source feed is enforced by `registry`. + * + * Fully permissionless: anyone can create, update, and migrate feeds — the + * verified `Update` is its own provenance proof. Predict-unaware: it owns no DUSDC + * conversion, forward derivation, freshness policy, or market-settlement + * valuation; callers own feed binding and freshness over timestamped reads. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as oracle_lane from './oracle_lane.js'; +const $moduleName = '@local-pkg/propbook::pyth_feed'; +export const RawSpot = new MoveStruct({ + name: `${$moduleName}::RawSpot`, + fields: { + pyth_source_id: bcs.u32(), + price_magnitude: bcs.u64(), + price_is_negative: bcs.bool(), + exponent_magnitude: bcs.u16(), + exponent_is_negative: bcs.bool(), + source_timestamp_us: bcs.u64(), + }, +}); +export const PythFeed = new MoveStruct({ + name: `${$moduleName}::PythFeed`, + fields: { + id: bcs.Address, + pyth_source_id: bcs.u32(), + /** + * Package version this feed runs at; updates require an exact match and `migrate` + * advances it forward-only after a package upgrade. + */ + version: bcs.u64(), + lane: oracle_lane.OracleLane(RawSpot), + }, +}); +export interface IdArguments { + feed: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [feed: RawTransactionArgument]; +} +/** Return the feed object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PythSourceIdArguments { + feed: RawTransactionArgument; +} +export interface PythSourceIdOptions { + package?: string; + arguments: PythSourceIdArguments | [feed: RawTransactionArgument]; +} +/** Return the configured Pyth source id. */ +export function pythSourceId(options: PythSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'pyth_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface VersionArguments { + feed: RawTransactionArgument; +} +export interface VersionOptions { + package?: string; + arguments: VersionArguments | [feed: RawTransactionArgument]; +} +/** Return the package version this feed runs at. */ +export function version(options: VersionOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'version', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSpotArguments { + feed: RawTransactionArgument; +} +export interface RawSpotOptions { + package?: string; + arguments: RawSpotArguments | [feed: RawTransactionArgument]; +} +/** + * Latest raw Pyth spot read. Aborts `ERawSpotNotFound` if no live update has + * landed. + */ +export function rawSpot(options: RawSpotOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_spot', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedSpotArguments { + feed: RawTransactionArgument; +} +export interface NormalizedSpotOptions { + package?: string; + arguments: NormalizedSpotArguments | [feed: RawTransactionArgument]; +} +/** Latest Propbook-normalized spot in 1e9 price scaling. */ +export function normalizedSpot(options: NormalizedSpotOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'normalized_spot', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSpotAtArguments { + feed: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface RawSpotAtOptions { + package?: string; + arguments: + | RawSpotAtArguments + | [feed: RawTransactionArgument, timestampMs: RawTransactionArgument]; +} +/** Exact raw Pyth spot read for `timestamp_ms`. */ +export function rawSpotAt(options: RawSpotAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_spot_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface NormalizedSpotAtArguments { + feed: RawTransactionArgument; + timestampMs: RawTransactionArgument; +} +export interface NormalizedSpotAtOptions { + package?: string; + arguments: + | NormalizedSpotAtArguments + | [feed: RawTransactionArgument, timestampMs: RawTransactionArgument]; +} +/** Exact Propbook-normalized spot in 1e9 price scaling for `timestamp_ms`. */ +export function normalizedSpotAt(options: NormalizedSpotAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u64'] satisfies (string | null)[]; + const parameterNames = ['feed', 'timestampMs']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'normalized_spot_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawPythSourceIdArguments { + raw: RawTransactionArgument; +} +export interface RawPythSourceIdOptions { + package?: string; + arguments: RawPythSourceIdArguments | [raw: RawTransactionArgument]; +} +export function rawPythSourceId(options: RawPythSourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_pyth_source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawPriceMagnitudeArguments { + raw: RawTransactionArgument; +} +export interface RawPriceMagnitudeOptions { + package?: string; + arguments: RawPriceMagnitudeArguments | [raw: RawTransactionArgument]; +} +export function rawPriceMagnitude(options: RawPriceMagnitudeOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_price_magnitude', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawPriceIsNegativeArguments { + raw: RawTransactionArgument; +} +export interface RawPriceIsNegativeOptions { + package?: string; + arguments: RawPriceIsNegativeArguments | [raw: RawTransactionArgument]; +} +export function rawPriceIsNegative(options: RawPriceIsNegativeOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_price_is_negative', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawExponentMagnitudeArguments { + raw: RawTransactionArgument; +} +export interface RawExponentMagnitudeOptions { + package?: string; + arguments: RawExponentMagnitudeArguments | [raw: RawTransactionArgument]; +} +export function rawExponentMagnitude(options: RawExponentMagnitudeOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_exponent_magnitude', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawExponentIsNegativeArguments { + raw: RawTransactionArgument; +} +export interface RawExponentIsNegativeOptions { + package?: string; + arguments: RawExponentIsNegativeArguments | [raw: RawTransactionArgument]; +} +export function rawExponentIsNegative(options: RawExponentIsNegativeOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_exponent_is_negative', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RawSourceTimestampUsArguments { + raw: RawTransactionArgument; +} +export interface RawSourceTimestampUsOptions { + package?: string; + arguments: RawSourceTimestampUsArguments | [raw: RawTransactionArgument]; +} +export function rawSourceTimestampUs(options: RawSourceTimestampUsOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['raw']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'raw_source_timestamp_us', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface UpdateArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface UpdateOptions { + package?: string; + arguments: + | UpdateArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** + * Decode a verified Pyth Lazer spot update, store it through the feed's generic + * oracle lane, then emit the update event. + */ +export function update(options: UpdateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'update', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface InsertAtArguments { + feed: RawTransactionArgument; + update: RawTransactionArgument; +} +export interface InsertAtOptions { + package?: string; + arguments: + | InsertAtArguments + | [feed: RawTransactionArgument, update: RawTransactionArgument]; +} +/** + * Insert an exact Pyth Lazer spot observation keyed by its exact millisecond + * source timestamp. Aborts `EInsertTimestampNotExactMillisecond` if the signed + * source timestamp is not a whole millisecond, so the exact-history key is an + * unambiguous millisecond a consumer can look up by equality. This does not mutate + * `latest`. + */ +export function insertAt(options: InsertAtOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, '0x2::clock::Clock'] satisfies (string | null)[]; + const parameterNames = ['feed', 'update']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'insert_at', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface MigrateArguments { + feed: RawTransactionArgument; +} +export interface MigrateOptions { + package?: string; + arguments: MigrateArguments | [feed: RawTransactionArgument]; +} +/** Migrate this feed to the running package version (forward-only). */ +export function migrate(options: MigrateOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['feed']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'pyth_feed', + function: 'migrate', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/propbook/registry.ts b/packages/deepbook-predict/src/contracts/propbook/registry.ts new file mode 100644 index 000000000..3ac2f3bfa --- /dev/null +++ b/packages/deepbook-predict/src/contracts/propbook/registry.ts @@ -0,0 +1,844 @@ +/************************************************************** + * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED * + **************************************************************/ + +/** + * Unified shared registry for Propbook oracle metadata. + * + * The registry owns two separate namespaces: + * + * - source catalog: one Propbook oracle object per source-local key + * - canonical binding: one immutable oracle per canonical consumer key + * + * Source oracle objects are permissionless wrappers around verified source data. + * Canonical bindings are admin-controlled because they are the trust claim that + * source data represents a Propbook underlying such as BTC. + * + * Intentionally NOT version-gated: a feed created under an old package version + * just seeds an old version and is migratable by the feed module, so a stale + * registry caller is harmless. + */ + +import { MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js'; +import { bcs } from '@mysten/sui/bcs'; +import { type Transaction } from '@mysten/sui/transactions'; +import * as table from './deps/sui/table.js'; +import * as table_1 from './deps/sui/table.js'; +import * as table_2 from './deps/sui/table.js'; +const $moduleName = '@local-pkg/propbook::registry'; +export const RegistryAdminCap = new MoveStruct({ + name: `${$moduleName}::RegistryAdminCap`, + fields: { + id: bcs.Address, + }, +}); +export const OracleRegistry = new MoveStruct({ + name: `${$moduleName}::OracleRegistry`, + fields: { + id: bcs.Address, + sources: table.Table, + bindings: table_1.Table, + source_bindings: table_2.Table, + }, +}); +export const OracleSourceKey = new MoveStruct({ + name: `${$moduleName}::OracleSourceKey`, + fields: { + oracle_kind: bcs.u8(), + source_id: bcs.u32(), + }, +}); +export const OracleBindingKey = new MoveStruct({ + name: `${$moduleName}::OracleBindingKey`, + fields: { + propbook_underlying_id: bcs.u32(), + oracle_kind: bcs.u8(), + value_kind: bcs.u8(), + }, +}); +export const OracleMetadata = new MoveStruct({ + name: `${$moduleName}::OracleMetadata`, + fields: { + propbook_underlying_id: bcs.u32(), + oracle_kind: bcs.u8(), + source_id: bcs.u32(), + propbook_oracle_id: bcs.Address, + value_kind: bcs.u8(), + }, +}); +export const OracleSourceRegistered = new MoveStruct({ + name: `${$moduleName}::OracleSourceRegistered`, + fields: { + oracle_kind: bcs.u8(), + source_id: bcs.u32(), + propbook_oracle_id: bcs.Address, + }, +}); +export const OracleBound = new MoveStruct({ + name: `${$moduleName}::OracleBound`, + fields: { + propbook_underlying_id: bcs.u32(), + oracle_kind: bcs.u8(), + source_id: bcs.u32(), + propbook_oracle_id: bcs.Address, + value_kind: bcs.u8(), + }, +}); +export interface IdArguments { + registry: RawTransactionArgument; +} +export interface IdOptions { + package?: string; + arguments: IdArguments | [registry: RawTransactionArgument]; +} +/** Return the registry object ID. */ +export function id(options: IdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['registry']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface RegistryAdminCapIdArguments { + cap: RawTransactionArgument; +} +export interface RegistryAdminCapIdOptions { + package?: string; + arguments: RegistryAdminCapIdArguments | [cap: RawTransactionArgument]; +} +/** Return the registry admin cap object ID. */ +export function registryAdminCapId(options: RegistryAdminCapIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['cap']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'registry_admin_cap_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ContainsPythSourceArguments { + registry: RawTransactionArgument; + pythSourceId: RawTransactionArgument; +} +export interface ContainsPythSourceOptions { + package?: string; + arguments: + | ContainsPythSourceArguments + | [registry: RawTransactionArgument, pythSourceId: RawTransactionArgument]; +} +/** Whether a Propbook Pyth source wrapper exists for `pyth_source_id`. */ +export function containsPythSource(options: ContainsPythSourceOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'pythSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'contains_pyth_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ContainsBlockScholesSpotSourceArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface ContainsBlockScholesSpotSourceOptions { + package?: string; + arguments: + | ContainsBlockScholesSpotSourceArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** Whether a Propbook BS spot wrapper exists for `bs_source_id`. */ +export function containsBlockScholesSpotSource(options: ContainsBlockScholesSpotSourceOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'contains_block_scholes_spot_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ContainsBlockScholesForwardSourceArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface ContainsBlockScholesForwardSourceOptions { + package?: string; + arguments: + | ContainsBlockScholesForwardSourceArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** Whether a Propbook BS forward wrapper exists for `bs_source_id`. */ +export function containsBlockScholesForwardSource( + options: ContainsBlockScholesForwardSourceOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'contains_block_scholes_forward_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ContainsBlockScholesSviSourceArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface ContainsBlockScholesSviSourceOptions { + package?: string; + arguments: + | ContainsBlockScholesSviSourceArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** Whether a Propbook BS SVI wrapper exists for `bs_source_id`. */ +export function containsBlockScholesSviSource(options: ContainsBlockScholesSviSourceOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'contains_block_scholes_svi_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookPythIdForSourceArguments { + registry: RawTransactionArgument; + pythSourceId: RawTransactionArgument; +} +export interface PropbookPythIdForSourceOptions { + package?: string; + arguments: + | PropbookPythIdForSourceArguments + | [registry: RawTransactionArgument, pythSourceId: RawTransactionArgument]; +} +/** Propbook Pyth object ID for a Pyth source id, if a wrapper exists. */ +export function propbookPythIdForSource(options: PropbookPythIdForSourceOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'pythSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_pyth_id_for_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookBlockScholesSpotIdForSourceArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface PropbookBlockScholesSpotIdForSourceOptions { + package?: string; + arguments: + | PropbookBlockScholesSpotIdForSourceArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** Propbook BS spot object ID for a BS source id, if a wrapper exists. */ +export function propbookBlockScholesSpotIdForSource( + options: PropbookBlockScholesSpotIdForSourceOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_block_scholes_spot_id_for_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookBlockScholesForwardIdForSourceArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface PropbookBlockScholesForwardIdForSourceOptions { + package?: string; + arguments: + | PropbookBlockScholesForwardIdForSourceArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** Propbook BS forward object ID for `bs_source_id`, if a wrapper exists. */ +export function propbookBlockScholesForwardIdForSource( + options: PropbookBlockScholesForwardIdForSourceOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_block_scholes_forward_id_for_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookBlockScholesSviIdForSourceArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface PropbookBlockScholesSviIdForSourceOptions { + package?: string; + arguments: + | PropbookBlockScholesSviIdForSourceArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** Propbook BS SVI object ID for `bs_source_id`, if a wrapper exists. */ +export function propbookBlockScholesSviIdForSource( + options: PropbookBlockScholesSviIdForSourceOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_block_scholes_svi_id_for_source', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookPythIdForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface PropbookPythIdForUnderlyingOptions { + package?: string; + arguments: + | PropbookPythIdForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical Propbook Pyth object ID for `propbook_underlying_id`, if bound. */ +export function propbookPythIdForUnderlying(options: PropbookPythIdForUnderlyingOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_pyth_id_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookBlockScholesSpotIdForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface PropbookBlockScholesSpotIdForUnderlyingOptions { + package?: string; + arguments: + | PropbookBlockScholesSpotIdForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical Propbook BS spot object ID for `propbook_underlying_id`, if bound. */ +export function propbookBlockScholesSpotIdForUnderlying( + options: PropbookBlockScholesSpotIdForUnderlyingOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_block_scholes_spot_id_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookBlockScholesForwardIdForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface PropbookBlockScholesForwardIdForUnderlyingOptions { + package?: string; + arguments: + | PropbookBlockScholesForwardIdForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical Propbook BS forward object ID for `propbook_underlying_id`, if bound. */ +export function propbookBlockScholesForwardIdForUnderlying( + options: PropbookBlockScholesForwardIdForUnderlyingOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_block_scholes_forward_id_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookBlockScholesSviIdForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface PropbookBlockScholesSviIdForUnderlyingOptions { + package?: string; + arguments: + | PropbookBlockScholesSviIdForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical Propbook BS SVI object ID for `propbook_underlying_id`, if bound. */ +export function propbookBlockScholesSviIdForUnderlying( + options: PropbookBlockScholesSviIdForUnderlyingOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_block_scholes_svi_id_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PythMetadataForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface PythMetadataForUnderlyingOptions { + package?: string; + arguments: + | PythMetadataForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical Pyth metadata for `propbook_underlying_id`, if bound. */ +export function pythMetadataForUnderlying(options: PythMetadataForUnderlyingOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'pyth_metadata_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BlockScholesSpotMetadataForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface BlockScholesSpotMetadataForUnderlyingOptions { + package?: string; + arguments: + | BlockScholesSpotMetadataForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical BS spot metadata for `propbook_underlying_id`, if bound. */ +export function blockScholesSpotMetadataForUnderlying( + options: BlockScholesSpotMetadataForUnderlyingOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'block_scholes_spot_metadata_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BlockScholesForwardMetadataForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface BlockScholesForwardMetadataForUnderlyingOptions { + package?: string; + arguments: + | BlockScholesForwardMetadataForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical BS forward metadata for `propbook_underlying_id`, if bound. */ +export function blockScholesForwardMetadataForUnderlying( + options: BlockScholesForwardMetadataForUnderlyingOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'block_scholes_forward_metadata_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BlockScholesSviMetadataForUnderlyingArguments { + registry: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface BlockScholesSviMetadataForUnderlyingOptions { + package?: string; + arguments: + | BlockScholesSviMetadataForUnderlyingArguments + | [ + registry: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Canonical BS SVI metadata for `propbook_underlying_id`, if bound. */ +export function blockScholesSviMetadataForUnderlying( + options: BlockScholesSviMetadataForUnderlyingOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'block_scholes_svi_metadata_for_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookUnderlyingIdArguments { + metadata: RawTransactionArgument; +} +export interface PropbookUnderlyingIdOptions { + package?: string; + arguments: PropbookUnderlyingIdArguments | [metadata: RawTransactionArgument]; +} +export function propbookUnderlyingId(options: PropbookUnderlyingIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['metadata']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_underlying_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface OracleKindArguments { + metadata: RawTransactionArgument; +} +export interface OracleKindOptions { + package?: string; + arguments: OracleKindArguments | [metadata: RawTransactionArgument]; +} +export function oracleKind(options: OracleKindOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['metadata']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'oracle_kind', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface SourceIdArguments { + metadata: RawTransactionArgument; +} +export interface SourceIdOptions { + package?: string; + arguments: SourceIdArguments | [metadata: RawTransactionArgument]; +} +export function sourceId(options: SourceIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['metadata']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'source_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface PropbookOracleIdArguments { + metadata: RawTransactionArgument; +} +export interface PropbookOracleIdOptions { + package?: string; + arguments: PropbookOracleIdArguments | [metadata: RawTransactionArgument]; +} +export function propbookOracleId(options: PropbookOracleIdOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['metadata']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'propbook_oracle_id', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface ValueKindArguments { + metadata: RawTransactionArgument; +} +export interface ValueKindOptions { + package?: string; + arguments: ValueKindArguments | [metadata: RawTransactionArgument]; +} +export function valueKind(options: ValueKindOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null] satisfies (string | null)[]; + const parameterNames = ['metadata']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'value_kind', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CreateAndSharePythFeedArguments { + registry: RawTransactionArgument; + pythSourceId: RawTransactionArgument; +} +export interface CreateAndSharePythFeedOptions { + package?: string; + arguments: + | CreateAndSharePythFeedArguments + | [registry: RawTransactionArgument, pythSourceId: RawTransactionArgument]; +} +/** + * Create and share the Propbook Pyth wrapper for `pyth_source_id`, then record it + * in the source catalog. Permissionless: a duplicate source aborts before object + * creation, and a junk source id creates an inert feed whose storage the caller + * pays for. + */ +export function createAndSharePythFeed(options: CreateAndSharePythFeedOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'pythSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'create_and_share_pyth_feed', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CreateAndShareBlockScholesSpotFeedArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface CreateAndShareBlockScholesSpotFeedOptions { + package?: string; + arguments: + | CreateAndShareBlockScholesSpotFeedArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** + * Create and share the Propbook BS spot wrapper for `bs_source_id`, then record it + * in the source catalog. Permissionless: a duplicate source aborts before object + * creation. + */ +export function createAndShareBlockScholesSpotFeed( + options: CreateAndShareBlockScholesSpotFeedOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'create_and_share_block_scholes_spot_feed', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CreateAndShareBlockScholesForwardFeedArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface CreateAndShareBlockScholesForwardFeedOptions { + package?: string; + arguments: + | CreateAndShareBlockScholesForwardFeedArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** + * Create and share the Propbook BS forward wrapper for `bs_source_id`, then record + * it in the source catalog. + */ +export function createAndShareBlockScholesForwardFeed( + options: CreateAndShareBlockScholesForwardFeedOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'create_and_share_block_scholes_forward_feed', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface CreateAndShareBlockScholesSviFeedArguments { + registry: RawTransactionArgument; + bsSourceId: RawTransactionArgument; +} +export interface CreateAndShareBlockScholesSviFeedOptions { + package?: string; + arguments: + | CreateAndShareBlockScholesSviFeedArguments + | [registry: RawTransactionArgument, bsSourceId: RawTransactionArgument]; +} +/** + * Create and share the Propbook BS SVI wrapper for `bs_source_id`, then record it + * in the source catalog. + */ +export function createAndShareBlockScholesSviFeed( + options: CreateAndShareBlockScholesSviFeedOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'bsSourceId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'create_and_share_block_scholes_svi_feed', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BindPythToUnderlyingArguments { + registry: RawTransactionArgument; + adminCap: RawTransactionArgument; + feed: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface BindPythToUnderlyingOptions { + package?: string; + arguments: + | BindPythToUnderlyingArguments + | [ + registry: RawTransactionArgument, + adminCap: RawTransactionArgument, + feed: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Admin-bind this Pyth source feed to a canonical Propbook underlying. */ +export function bindPythToUnderlying(options: BindPythToUnderlyingOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'adminCap', 'feed', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'bind_pyth_to_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BindBlockScholesSpotToUnderlyingArguments { + registry: RawTransactionArgument; + adminCap: RawTransactionArgument; + feed: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface BindBlockScholesSpotToUnderlyingOptions { + package?: string; + arguments: + | BindBlockScholesSpotToUnderlyingArguments + | [ + registry: RawTransactionArgument, + adminCap: RawTransactionArgument, + feed: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** Admin-bind this BS spot source feed to a canonical Propbook underlying. */ +export function bindBlockScholesSpotToUnderlying(options: BindBlockScholesSpotToUnderlyingOptions) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'adminCap', 'feed', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'bind_block_scholes_spot_to_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} +export interface BindBlockScholesSurfaceToUnderlyingArguments { + registry: RawTransactionArgument; + adminCap: RawTransactionArgument; + forwardFeed: RawTransactionArgument; + sviFeed: RawTransactionArgument; + propbookUnderlyingId: RawTransactionArgument; +} +export interface BindBlockScholesSurfaceToUnderlyingOptions { + package?: string; + arguments: + | BindBlockScholesSurfaceToUnderlyingArguments + | [ + registry: RawTransactionArgument, + adminCap: RawTransactionArgument, + forwardFeed: RawTransactionArgument, + sviFeed: RawTransactionArgument, + propbookUnderlyingId: RawTransactionArgument, + ]; +} +/** + * Admin-bind this BS forward/SVI surface pair to a canonical Propbook underlying. + * The underlying's BS spot feed must already be bound, and all three BS feeds must + * come from the same source id. + */ +export function bindBlockScholesSurfaceToUnderlying( + options: BindBlockScholesSurfaceToUnderlyingOptions, +) { + const packageAddress = options.package ?? '@local-pkg/propbook'; + const argumentsTypes = [null, null, null, null, 'u32'] satisfies (string | null)[]; + const parameterNames = ['registry', 'adminCap', 'forwardFeed', 'sviFeed', 'propbookUnderlyingId']; + return (tx: Transaction) => + tx.moveCall({ + package: packageAddress, + module: 'registry', + function: 'bind_block_scholes_surface_to_underlying', + arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames), + }); +} diff --git a/packages/deepbook-predict/src/contracts/utils/index.ts b/packages/deepbook-predict/src/contracts/utils/index.ts new file mode 100644 index 000000000..639dc95be --- /dev/null +++ b/packages/deepbook-predict/src/contracts/utils/index.ts @@ -0,0 +1,234 @@ +import { + bcs, + type BcsType, + type TypeTag, + TypeTagSerializer, + BcsStruct, + BcsEnum, + BcsTuple, +} from '@mysten/sui/bcs'; +import { normalizeSuiAddress } from '@mysten/sui/utils'; +import { type TransactionArgument, isArgument } from '@mysten/sui/transactions'; +import { type ClientWithCoreApi, type SuiClientTypes } from '@mysten/sui/client'; + +const MOVE_STDLIB_ADDRESS = normalizeSuiAddress('0x1'); +const SUI_FRAMEWORK_ADDRESS = normalizeSuiAddress('0x2'); + +export type RawTransactionArgument = T | TransactionArgument; + +export interface GetOptions< + Include extends Omit = {}, +> extends SuiClientTypes.GetObjectOptions { + client: ClientWithCoreApi; +} + +export interface GetManyOptions< + Include extends Omit = {}, +> extends SuiClientTypes.GetObjectsOptions { + client: ClientWithCoreApi; +} + +export function getPureBcsSchema(typeTag: string | TypeTag): BcsType | null { + const parsedTag = typeof typeTag === 'string' ? TypeTagSerializer.parseFromStr(typeTag) : typeTag; + + if ('u8' in parsedTag) { + return bcs.U8; + } else if ('u16' in parsedTag) { + return bcs.U16; + } else if ('u32' in parsedTag) { + return bcs.U32; + } else if ('u64' in parsedTag) { + return bcs.U64; + } else if ('u128' in parsedTag) { + return bcs.U128; + } else if ('u256' in parsedTag) { + return bcs.U256; + } else if ('address' in parsedTag) { + return bcs.Address; + } else if ('bool' in parsedTag) { + return bcs.Bool; + } else if ('vector' in parsedTag) { + const type = getPureBcsSchema(parsedTag.vector); + return type ? bcs.vector(type) : null; + } else if ('struct' in parsedTag) { + const structTag = parsedTag.struct; + const pkg = normalizeSuiAddress(structTag.address); + + if (pkg === MOVE_STDLIB_ADDRESS) { + if ( + (structTag.module === 'ascii' || structTag.module === 'string') && + structTag.name === 'String' + ) { + return bcs.String; + } + + if (structTag.module === 'option' && structTag.name === 'Option') { + const type = getPureBcsSchema(structTag.typeParams[0]); + return type ? bcs.option(type) : null; + } + } + + if ( + pkg === SUI_FRAMEWORK_ADDRESS && + structTag.module === 'object' && + (structTag.name === 'ID' || structTag.name === 'UID') + ) { + return bcs.Address; + } + } + + return null; +} + +export function normalizeMoveArguments( + args: unknown[] | object, + argTypes: readonly (string | null)[], + parameterNames?: string[], +) { + const argLen = Array.isArray(args) ? args.length : Object.keys(args).length; + if (parameterNames && argLen !== parameterNames.length) { + throw new Error( + `Invalid number of arguments, expected ${parameterNames.length}, got ${argLen}`, + ); + } + + const normalizedArgs: TransactionArgument[] = []; + + let index = 0; + for (const [i, argType] of argTypes.entries()) { + if (argType === '0x2::clock::Clock') { + normalizedArgs.push((tx) => tx.object.clock()); + continue; + } + + if (argType === '0x2::random::Random') { + normalizedArgs.push((tx) => tx.object.random()); + continue; + } + + if (argType === '0x2::deny_list::DenyList') { + normalizedArgs.push((tx) => tx.object.denyList()); + continue; + } + + if (argType === '0x3::sui_system::SuiSystemState') { + normalizedArgs.push((tx) => tx.object.system()); + continue; + } + + let arg; + if (Array.isArray(args)) { + if (index >= args.length) { + throw new Error( + `Invalid number of arguments, expected at least ${index + 1}, got ${args.length}`, + ); + } + arg = args[index]; + } else { + if (!parameterNames) { + throw new Error(`Expected arguments to be passed as an array`); + } + const name = parameterNames[index]; + arg = args[name as keyof typeof args]; + + if (arg === undefined) { + throw new Error(`Parameter ${name} is required`); + } + } + + index += 1; + + if (typeof arg === 'function' || isArgument(arg)) { + normalizedArgs.push(arg as TransactionArgument); + continue; + } + + const type = argTypes[i]; + const bcsType = type === null ? null : getPureBcsSchema(type); + + if (bcsType) { + const bytes = bcsType.serialize(arg as never); + normalizedArgs.push((tx) => tx.pure(bytes)); + continue; + } else if (typeof arg === 'string') { + normalizedArgs.push((tx) => tx.object(arg)); + continue; + } + + throw new Error(`Invalid argument ${stringify(arg)} for type ${type}`); + } + + return normalizedArgs; +} + +export class MoveStruct< + T extends Record>, + const Name extends string = string, +> extends BcsStruct { + async get = {}>({ + objectId, + ...options + }: GetOptions): Promise< + SuiClientTypes.Object & { + json: BcsStruct['$inferType']; + } + > { + const [res] = await this.getMany({ + ...options, + objectIds: [objectId], + }); + + return res; + } + + async getMany = {}>({ + client, + ...options + }: GetManyOptions): Promise< + Array< + SuiClientTypes.Object & { + json: BcsStruct['$inferType']; + } + > + > { + const response = (await client.core.getObjects({ + ...options, + include: { + ...options.include, + content: true, + }, + })) as SuiClientTypes.GetObjectsResponse; + + return response.objects.map((obj) => { + if (obj instanceof Error) { + throw obj; + } + + return { + ...obj, + json: this.parse(obj.content), + }; + }); + } +} + +export class MoveEnum< + T extends Record | null>, + const Name extends string, +> extends BcsEnum {} + +export class MoveTuple< + const T extends readonly BcsType[], + const Name extends string, +> extends BcsTuple {} + +function stringify(val: unknown) { + if (typeof val === 'object') { + return JSON.stringify(val, (val: unknown) => val); + } + if (typeof val === 'bigint') { + return val.toString(); + } + + return val; +} diff --git a/packages/deepbook-predict/src/index.ts b/packages/deepbook-predict/src/index.ts new file mode 100644 index 000000000..3f88fa01b --- /dev/null +++ b/packages/deepbook-predict/src/index.ts @@ -0,0 +1,48 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Configuration +export { PredictConfig } from './utils/config.js'; +export type { PredictConfigOptions, PredictIds, PredictNetwork } from './utils/config.js'; + +// Protocol constants +export * from './utils/constants.js'; + +// Order-ID codec (mirror of `deepbook_predict::order`) +export { decodeOrderId, encodeOrderId, quantityToLots } from './types/orderId.js'; +export type { DecodedOrder, OrderTerms } from './types/orderId.js'; + +// Client facade +export { PredictClient, predict } from './client.js'; +export type { PredictClientOptions, PredictCompatibleClient, PredictOptions } from './client.js'; + +// Transaction builders +export { AccountContract } from './transactions/account.js'; +export { PredictAccountContract } from './transactions/predictAccount.js'; +export { TradeContract } from './transactions/trade.js'; +export type { PricerFeeds } from './transactions/trade.js'; +export { LpContract } from './transactions/lp.js'; +export { FlushContract } from './transactions/flush.js'; + +// On-chain queries +export { MarketQueries } from './queries/marketQueries.js'; +export type { MarketState } from './queries/marketQueries.js'; +export { VaultQueries } from './queries/vaultQueries.js'; +export type { VaultState } from './queries/vaultQueries.js'; +export type { QueryContext } from './queries/context.js'; + +// Indexer client +export { IndexerClient } from './queries/indexerClient.js'; +export type { + FetchLike, + FlushExecuted, + IndexerClientOptions, + IndexerEvent, + LpRequestState, + MarketCreated, + MarketOpenInterest, + OrderState, + PredictManagerCreated, + StatusResponse, + TimeWindow, +} from './queries/indexerClient.js'; diff --git a/packages/deepbook-predict/src/queries/context.ts b/packages/deepbook-predict/src/queries/context.ts new file mode 100644 index 000000000..aa1078c27 --- /dev/null +++ b/packages/deepbook-predict/src/queries/context.ts @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import type { PredictCompatibleClient } from '../client.js'; +import type { PredictConfig } from '../utils/config.js'; + +/** Shared context handed to every on-chain query class. */ +export interface QueryContext { + client: PredictCompatibleClient; + config: PredictConfig; + address: string; +} diff --git a/packages/deepbook-predict/src/queries/decode.ts b/packages/deepbook-predict/src/queries/decode.ts new file mode 100644 index 000000000..1eb10fdd0 --- /dev/null +++ b/packages/deepbook-predict/src/queries/decode.ts @@ -0,0 +1,36 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { bcs } from '@mysten/sui/bcs'; + +/** + * Shape of the subset of `client.core.simulateTransaction` results the query layer + * reads. Kept minimal so the queries can be unit-tested with a stub client. + */ +export interface SimulateResult { + commandResults?: Array<{ returnValues: Array<{ bcs: Uint8Array | number[] }> }> | null; +} + +/** Raw bytes of the first return value of command `index`. */ +export function returnBytes(res: SimulateResult, index: number): Uint8Array { + const command = res.commandResults?.[index]; + if (!command) { + throw new Error(`simulate result missing command ${index}`); + } + return new Uint8Array(command.returnValues[0].bcs); +} + +export const parseU64 = (res: SimulateResult, index: number): bigint => + BigInt(bcs.u64().parse(returnBytes(res, index))); + +export const parseU32 = (res: SimulateResult, index: number): number => + bcs.u32().parse(returnBytes(res, index)); + +export const parseBool = (res: SimulateResult, index: number): boolean => + bcs.bool().parse(returnBytes(res, index)); + +export const parseOptionAddress = (res: SimulateResult, index: number): string | null => + bcs.option(bcs.Address).parse(returnBytes(res, index)); + +export const parseAddressVector = (res: SimulateResult, index: number): string[] => + bcs.vector(bcs.Address).parse(returnBytes(res, index)); diff --git a/packages/deepbook-predict/src/queries/indexerClient.ts b/packages/deepbook-predict/src/queries/indexerClient.ts new file mode 100644 index 000000000..5bfd4014c --- /dev/null +++ b/packages/deepbook-predict/src/queries/indexerClient.ts @@ -0,0 +1,227 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Typed client for the `predict-server` indexer HTTP API. Endpoints are historical / +// aggregated reads; point-in-time chain truth comes from the on-chain query classes. +// +// Numeric note: the server encodes monetary/share/NAV values as arbitrary-precision +// JSON numbers (Rust `BigDecimal`). Parsed via `JSON.parse` they become JS `number` +// and lose precision above 2^53. They are typed `number` here; a precision-preserving +// parse is a follow-up. i64 fields (checkpoints, ms timestamps, 1e9 ratios) are safe. +// +// Pagination is time-window + limit only (no cursor): `startTime`/`endTime` are unix +// SECONDS; `limit` defaults to 50 and is clamped to [1, 500]. + +export type FetchLike = ( + input: string, + init?: { signal?: AbortSignal }, +) => Promise<{ + ok: boolean; + status: number; + statusText: string; + json: () => Promise; +}>; + +export interface IndexerClientOptions { + baseUrl: string; + /** Custom fetch (defaults to the global `fetch`); useful for tests / custom transports. */ + fetch?: FetchLike; +} + +/** Time-window + limit params shared by list endpoints. `startTime`/`endTime` are unix seconds. */ +export interface TimeWindow { + startTime?: number; + endTime?: number; + limit?: number; +} + +export interface StatusResponse { + status: 'OK' | 'UNHEALTHY'; + latest_onchain_checkpoint: number; + current_time_ms: number; + earliest_checkpoint: number; + max_lag_pipeline: string; + pipelines: Array<{ + pipeline: string; + indexed_checkpoint: number; + indexed_timestamp_ms: number; + checkpoint_lag: number; + time_lag_seconds: number; + is_backfill: boolean; + }>; +} + +export interface MarketCreated { + kind: 'market_created'; + expiry_market_id: string; + pool_vault_id: string; + propbook_underlying_id: number; + expiry: number; + tick_size: number; +} + +export interface PredictManagerCreated { + kind: 'predict_manager_created'; + predict_manager_id: string; + balance_manager_id: string; + owner: string; +} + +/** A maintained current-state position row (`order_state`). `status` ∈ open|replaced|closed|liquidated|liquidated_redeemed|settled_redeemed. */ +export interface OrderState { + kind: 'order_state'; + expiry_market_id: string; + order_id: string; + predict_manager_id: string | null; + position_root_id: string | null; + owner: string | null; + status: string; + replacement_order_id: string | null; + opened_at_ms: number; + lower_boundary_index: number; + higher_boundary_index: number; + floor_shares: number; + quantity: number; + sequence: number; + leverage: number | null; + entry_probability: number | null; + net_premium: number | null; + updated_at_ms: number; +} + +/** A maintained current-state LP request row (`lp_request_state`). `status` ∈ open|cancelled|filled. */ +export interface LpRequestState { + kind: 'lp_request_state'; + pool_vault_id: string; + is_supply: boolean; + request_index: number; + predict_manager_id: string | null; + recipient: string | null; + requested_amount: number | null; + status: string; + filled_dusdc: number | null; + filled_shares: number | null; + opened_at_ms: number; + updated_at_ms: number; +} + +export interface FlushExecuted { + kind: 'flush_executed'; + pool_vault_id: string; + epoch: number; + pool_value: number; + total_supply: number; + active_market_nav: number; + market_count: number; + idle_balance_before: number; + supplies_filled: number; + withdrawals_filled: number; + requests_processed: number; + idle_balance_after: number; +} + +export interface MarketOpenInterest { + expiry_market_id: string; + open_order_count: number; + open_quantity: string; + open_floor_shares: string; +} + +/** A raw indexed event row; discriminate union feeds on `kind`. */ +export type IndexerEvent = { kind: string } & Record; + +const STATUS_FILTER = 'open'; + +export class IndexerClient { + #baseUrl: string; + #fetch: FetchLike; + + constructor(options: IndexerClientOptions) { + this.#baseUrl = options.baseUrl.replace(/\/+$/, ''); + this.#fetch = options.fetch ?? (globalThis.fetch as unknown as FetchLike); + } + + async #get(path: string, query?: Record): Promise { + const search = new URLSearchParams(); + if (query) { + for (const [key, value] of Object.entries(query)) { + if (value !== undefined) { + search.set(key, String(value)); + } + } + } + const qs = search.toString(); + const url = `${this.#baseUrl}${path}${qs ? `?${qs}` : ''}`; + const res = await this.#fetch(url); + if (!res.ok) { + throw new Error(`predict-server ${path} failed: ${res.status} ${res.statusText}`); + } + return (await res.json()) as T; + } + + #window(w?: TimeWindow): Record { + return { start_time: w?.startTime, end_time: w?.endTime, limit: w?.limit }; + } + + getStatus(params?: { + maxCheckpointLag?: number; + maxTimeLagSeconds?: number; + }): Promise { + return this.#get('/status', { + max_checkpoint_lag: params?.maxCheckpointLag, + max_time_lag_seconds: params?.maxTimeLagSeconds, + }); + } + + listMarkets(window?: TimeWindow): Promise { + return this.#get('/markets', this.#window(window)); + } + + getMarketOrders(marketId: string, window?: TimeWindow): Promise { + return this.#get(`/markets/${marketId}/orders`, this.#window(window)); + } + + getMarketState(marketId: string): Promise> { + return this.#get(`/markets/${marketId}/state`); + } + + getMarketOpenInterest(marketId: string): Promise { + return this.#get(`/markets/${marketId}/open-interest`); + } + + getManagers(params?: { owner?: string } & TimeWindow): Promise { + return this.#get('/managers', { owner: params?.owner, ...this.#window(params) }); + } + + getManagerOrders(managerId: string, window?: TimeWindow): Promise { + return this.#get(`/managers/${managerId}/orders`, this.#window(window)); + } + + getManagerPositions( + managerId: string, + params?: { status?: string } & TimeWindow, + ): Promise { + return this.#get(`/managers/${managerId}/positions`, { + status: params?.status ?? STATUS_FILTER, + ...this.#window(params), + }); + } + + getManagerLpRequests( + managerId: string, + params?: { status?: string } & TimeWindow, + ): Promise { + return this.#get(`/managers/${managerId}/lp-requests`, { + status: params?.status ?? STATUS_FILTER, + ...this.#window(params), + }); + } + + getVaultFlushes(vaultId: string, window?: TimeWindow): Promise { + return this.#get(`/vaults/${vaultId}/flushes`, this.#window(window)); + } + + getVaultState(vaultId: string): Promise> { + return this.#get(`/vaults/${vaultId}/state`); + } +} diff --git a/packages/deepbook-predict/src/queries/marketQueries.ts b/packages/deepbook-predict/src/queries/marketQueries.ts new file mode 100644 index 000000000..91bb4142a --- /dev/null +++ b/packages/deepbook-predict/src/queries/marketQueries.ts @@ -0,0 +1,140 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { Transaction } from '@mysten/sui/transactions'; + +import * as expiryMarket from '../contracts/deepbook_predict/expiry_market.js'; +import * as propbookRegistry from '../contracts/propbook/registry.js'; +import type { PricerFeeds } from '../transactions/trade.js'; +import type { QueryContext } from './context.js'; +import { + parseBool, + parseOptionAddress, + parseU32, + parseU64, + type SimulateResult, +} from './decode.js'; + +/** Decoded scalar state of an expiry market (raw on-chain units). */ +export interface MarketState { + propbookUnderlyingId: number; + expiry: bigint; + tickSize: bigint; + cashBalance: bigint; + requiredCash: bigint; + mintPaused: boolean; +} + +/** + * On-chain reads of expiry-market state via `client.core.simulateTransaction`. These + * getters take the market object directly (no `&Account` borrow), so they compose in + * a single inspect PTB. + */ +export class MarketQueries { + #ctx: QueryContext; + + constructor(ctx: QueryContext) { + this.#ctx = ctx; + } + + get #predictPackageId() { + return this.#ctx.config.ids.predictPackageId; + } + + async #simulate(tx: Transaction): Promise { + return this.#ctx.client.core.simulateTransaction({ + transaction: tx, + include: { commandResults: true, effects: true }, + }); + } + + /** Read the scalar state fields of a market in one inspect. */ + async getMarketState(market: string): Promise { + const pkg = this.#predictPackageId; + const tx = new Transaction(); + tx.setSender(this.#ctx.address); + tx.add(expiryMarket.propbookUnderlyingId({ package: pkg, arguments: { market } })); + tx.add(expiryMarket.expiry({ package: pkg, arguments: { market } })); + tx.add(expiryMarket.tickSize({ package: pkg, arguments: { market } })); + tx.add(expiryMarket.cashBalance({ package: pkg, arguments: { market } })); + tx.add(expiryMarket.requiredCash({ package: pkg, arguments: { market } })); + tx.add(expiryMarket.mintPaused({ package: pkg, arguments: { market } })); + + const res = await this.#simulate(tx); + return { + propbookUnderlyingId: parseU32(res, 0), + expiry: parseU64(res, 1), + tickSize: parseU64(res, 2), + cashBalance: parseU64(res, 3), + requiredCash: parseU64(res, 4), + mintPaused: parseBool(res, 5), + }; + } + + /** + * Resolve the four canonical propbook feed ids for a market's underlying (for + * {@link PricerFeeds}). Throws if any feed is unbound. + */ + async resolveFeeds(market: string, propbookUnderlyingId?: number): Promise { + const underlyingId = + propbookUnderlyingId ?? (await this.getMarketState(market)).propbookUnderlyingId; + const pkg = this.#ctx.config.ids.propbookPackageId; + const registry = this.#ctx.config.ids.oracleRegistryId; + const args = { registry, propbookUnderlyingId: underlyingId }; + + const tx = new Transaction(); + tx.setSender(this.#ctx.address); + tx.add(propbookRegistry.propbookPythIdForUnderlying({ package: pkg, arguments: args })); + tx.add( + propbookRegistry.propbookBlockScholesSpotIdForUnderlying({ package: pkg, arguments: args }), + ); + tx.add( + propbookRegistry.propbookBlockScholesForwardIdForUnderlying({ + package: pkg, + arguments: args, + }), + ); + tx.add( + propbookRegistry.propbookBlockScholesSviIdForUnderlying({ package: pkg, arguments: args }), + ); + + const res = await this.#simulate(tx); + const pyth = parseOptionAddress(res, 0); + const bsSpot = parseOptionAddress(res, 1); + const bsForward = parseOptionAddress(res, 2); + const bsSvi = parseOptionAddress(res, 3); + if (!pyth || !bsSpot || !bsForward || !bsSvi) { + throw new Error(`market ${market} has unbound propbook feeds for underlying ${underlyingId}`); + } + return { pyth, bsSpot, bsForward, bsSvi }; + } + + /** + * Exact live NAV of a market. Loads a pricer and reads `current_nav` in one inspect. + * Pass `feeds` to skip the feed-resolution round trip. + */ + async currentNav(market: string, feeds?: PricerFeeds): Promise { + const resolved = feeds ?? (await this.resolveFeeds(market)); + const pkg = this.#predictPackageId; + const tx = new Transaction(); + tx.setSender(this.#ctx.address); + const pricer = tx.add( + expiryMarket.loadLivePricer({ + package: pkg, + arguments: { + market, + config: this.#ctx.config.ids.protocolConfigId, + propbookRegistry: this.#ctx.config.ids.oracleRegistryId, + pyth: resolved.pyth, + bsSpot: resolved.bsSpot, + bsForward: resolved.bsForward, + bsSvi: resolved.bsSvi, + }, + }), + ); + tx.add(expiryMarket.currentNav({ package: pkg, arguments: { market, pricer } })); + + const res = await this.#simulate(tx); + return parseU64(res, 1); + } +} diff --git a/packages/deepbook-predict/src/queries/queries.test.ts b/packages/deepbook-predict/src/queries/queries.test.ts new file mode 100644 index 000000000..5fa19b299 --- /dev/null +++ b/packages/deepbook-predict/src/queries/queries.test.ts @@ -0,0 +1,158 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { bcs } from '@mysten/sui/bcs'; +import { describe, expect, it } from 'vitest'; + +import type { PredictCompatibleClient } from '../client.js'; +import { PredictConfig } from '../utils/config.js'; +import type { PredictIds } from '../utils/config.js'; +import type { PricerFeeds } from '../transactions/trade.js'; +import type { QueryContext } from './context.js'; +import { IndexerClient } from './indexerClient.js'; +import type { FetchLike } from './indexerClient.js'; +import { MarketQueries } from './marketQueries.js'; +import { VaultQueries } from './vaultQueries.js'; + +const A = (n: number) => `0x${n.toString(16).padStart(64, '0')}`; +const IDS: PredictIds = { + predictPackageId: A(0x101), + accountPackageId: A(0x102), + propbookPackageId: A(0x103), + registryId: A(0x104), + poolVaultId: A(0x105), + protocolConfigId: A(0x106), + oracleRegistryId: A(0x107), + accountRegistryId: A(0x108), + dusdcType: `${A(0x109)}::dusdc::DUSDC`, +}; +const config = new PredictConfig({ network: 'testnet', address: A(0xa11ce), ids: IDS }); +const FEEDS: PricerFeeds = { + pyth: A(0x301), + bsSpot: A(0x302), + bsForward: A(0x303), + bsSvi: A(0x304), +}; + +const u64 = (v: bigint) => bcs.u64().serialize(v).toBytes(); +const optAddr = (v: string | null) => bcs.option(bcs.Address).serialize(v).toBytes(); + +/** Stub client: `commands[i]` is the list of return-value byte arrays for command i. */ +function stubClient(commands: Uint8Array[][]): PredictCompatibleClient { + return { + core: { + async simulateTransaction() { + return { + commandResults: commands.map((rvs) => ({ + returnValues: rvs.map((bytes) => ({ bcs: bytes })), + })), + }; + }, + }, + } as unknown as PredictCompatibleClient; +} + +const ctx = (client: PredictCompatibleClient): QueryContext => ({ + client, + config, + address: A(0xa11ce), +}); + +describe('MarketQueries decode', () => { + it('currentNav decodes the second command return (u64)', async () => { + const client = stubClient([[], [u64(4_242n)]]); + const nav = await new MarketQueries(ctx(client)).currentNav(A(0x202), FEEDS); + expect(nav).toBe(4_242n); + }); + + it('resolveFeeds returns the four bound feed ids', async () => { + const client = stubClient([ + [optAddr(A(0x301))], + [optAddr(A(0x302))], + [optAddr(A(0x303))], + [optAddr(A(0x304))], + ]); + const feeds = await new MarketQueries(ctx(client)).resolveFeeds(A(0x202), 7); + expect(feeds).toEqual(FEEDS); + }); + + it('resolveFeeds throws when a feed is unbound', async () => { + const client = stubClient([ + [optAddr(A(0x301))], + [optAddr(null)], + [optAddr(A(0x303))], + [optAddr(A(0x304))], + ]); + await expect(new MarketQueries(ctx(client)).resolveFeeds(A(0x202), 7)).rejects.toThrow(); + }); +}); + +describe('VaultQueries decode', () => { + it('getVaultState decodes each getter by command index', async () => { + const client = stubClient([ + [u64(1n)], + [u64(2n)], + [u64(3n)], + [u64(4n)], + [u64(5n)], + [u64(6n)], + [u64(7n)], + [u64(8n)], + ]); + const state = await new VaultQueries(ctx(client)).getVaultState(); + expect(state).toEqual({ + idleBalance: 1n, + plpTotalSupply: 2n, + stakedDeep: 3n, + protocolReserveBalance: 4n, + feeIncentiveReserve: 5n, + supplyRequestsPending: 6n, + withdrawRequestsPending: 7n, + pendingProtocolProfit: 8n, + }); + }); +}); + +describe('IndexerClient URL building', () => { + function recorder() { + const urls: string[] = []; + const fetch: FetchLike = async (url) => { + urls.push(url); + return { ok: true, status: 200, statusText: 'OK', json: async () => [] }; + }; + return { urls, fetch }; + } + + it('strips the trailing slash and omits an empty query', async () => { + const { urls, fetch } = recorder(); + await new IndexerClient({ baseUrl: 'https://idx.example/', fetch }).listMarkets(); + expect(urls[0]).toBe('https://idx.example/markets'); + }); + + it('serializes the time window (seconds) and limit, skipping undefined', async () => { + const { urls, fetch } = recorder(); + await new IndexerClient({ baseUrl: 'https://idx.example', fetch }).listMarkets({ + startTime: 5, + limit: 10, + }); + expect(urls[0]).toBe('https://idx.example/markets?start_time=5&limit=10'); + }); + + it('defaults manager positions to the open status filter', async () => { + const { urls, fetch } = recorder(); + await new IndexerClient({ baseUrl: 'https://idx.example', fetch }).getManagerPositions(A(0x1)); + expect(urls[0]).toBe(`https://idx.example/managers/${A(0x1)}/positions?status=open`); + }); + + it('throws on a non-ok response', async () => { + const fetch: FetchLike = async () => ({ + ok: false, + status: 503, + statusText: 'Service Unavailable', + json: async () => ({}), + }); + await expect( + new IndexerClient({ baseUrl: 'https://idx.example', fetch }).getStatus(), + ).rejects.toThrow(); + }); +}); diff --git a/packages/deepbook-predict/src/queries/vaultQueries.ts b/packages/deepbook-predict/src/queries/vaultQueries.ts new file mode 100644 index 000000000..760cc19ea --- /dev/null +++ b/packages/deepbook-predict/src/queries/vaultQueries.ts @@ -0,0 +1,86 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { Transaction } from '@mysten/sui/transactions'; + +import * as plp from '../contracts/deepbook_predict/plp.js'; +import type { QueryContext } from './context.js'; +import { parseAddressVector, parseU64, type SimulateResult } from './decode.js'; + +/** Decoded scalar state of the shared pool vault (raw on-chain units). */ +export interface VaultState { + idleBalance: bigint; + plpTotalSupply: bigint; + stakedDeep: bigint; + protocolReserveBalance: bigint; + feeIncentiveReserve: bigint; + supplyRequestsPending: bigint; + withdrawRequestsPending: bigint; + pendingProtocolProfit: bigint; +} + +/** On-chain reads of pool-vault state via `client.core.simulateTransaction`. */ +export class VaultQueries { + #ctx: QueryContext; + + constructor(ctx: QueryContext) { + this.#ctx = ctx; + } + + get #vault() { + return this.#ctx.config.ids.poolVaultId; + } + + get #predictPackageId() { + return this.#ctx.config.ids.predictPackageId; + } + + async #simulate(tx: Transaction): Promise { + return this.#ctx.client.core.simulateTransaction({ + transaction: tx, + include: { commandResults: true, effects: true }, + }); + } + + /** Read the vault's balance/accounting scalars in one inspect. */ + async getVaultState(): Promise { + const pkg = this.#predictPackageId; + const vault = this.#vault; + const tx = new Transaction(); + tx.setSender(this.#ctx.address); + tx.add(plp.idleBalance({ package: pkg, arguments: { vault } })); + tx.add(plp.plpTotalSupply({ package: pkg, arguments: { vault } })); + tx.add(plp.stakedDeep({ package: pkg, arguments: { vault } })); + tx.add(plp.protocolReserveBalance({ package: pkg, arguments: { vault } })); + tx.add(plp.feeIncentiveReserve({ package: pkg, arguments: { vault } })); + tx.add(plp.supplyRequestsPending({ package: pkg, arguments: { vault } })); + tx.add(plp.withdrawRequestsPending({ package: pkg, arguments: { vault } })); + tx.add(plp.pendingProtocolProfit({ package: pkg, arguments: { vault } })); + + const res = await this.#simulate(tx); + return { + idleBalance: parseU64(res, 0), + plpTotalSupply: parseU64(res, 1), + stakedDeep: parseU64(res, 2), + protocolReserveBalance: parseU64(res, 3), + feeIncentiveReserve: parseU64(res, 4), + supplyRequestsPending: parseU64(res, 5), + withdrawRequestsPending: parseU64(res, 6), + pendingProtocolProfit: parseU64(res, 7), + }; + } + + /** The set of active expiry markets (their object ids) that a flush must value. */ + async activeExpiryMarkets(): Promise { + const tx = new Transaction(); + tx.setSender(this.#ctx.address); + tx.add( + plp.activeExpiryMarkets({ + package: this.#predictPackageId, + arguments: { vault: this.#vault }, + }), + ); + const res = await this.#simulate(tx); + return parseAddressVector(res, 0); + } +} diff --git a/packages/deepbook-predict/src/transactions/account.ts b/packages/deepbook-predict/src/transactions/account.ts new file mode 100644 index 000000000..818b62c84 --- /dev/null +++ b/packages/deepbook-predict/src/transactions/account.ts @@ -0,0 +1,106 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { coinWithBalance } from '@mysten/sui/transactions'; +import type { Transaction, TransactionObjectArgument } from '@mysten/sui/transactions'; + +import * as account from '../contracts/account/account.js'; +import * as accountRegistry from '../contracts/account/account_registry.js'; +import type { PredictConfig } from '../utils/config.js'; +import { ACCUMULATOR_ROOT_ID } from '../utils/constants.js'; + +/** + * Custody flows over the `account` package (the primitive Predict trades against). + * + * Each trader has one shared `AccountWrapper` (created once via the account registry). + * Owner actions consume a fresh `Auth` hot-potato minted in the same PTB via + * `account::generate_auth` (derived from the tx sender), so set the sender before + * signing. The `Clock` is auto-injected by the generated bindings; `AccumulatorRoot` + * (`0xacc`) is passed explicitly because custody calls settle accumulator funds first. + */ +export class AccountContract { + #config: PredictConfig; + + constructor(config: PredictConfig) { + this.#config = config; + } + + get #accountPackageId() { + return this.#config.ids.accountPackageId; + } + + #setSender(tx: Transaction) { + if (this.#config.address) { + tx.setSenderIfNotSet(this.#config.address); + } + } + + /** Mint a fresh owner `Auth` from the tx sender. Consumed by the next custody/trade call. */ + generateAuth = () => (tx: Transaction) => { + this.#setSender(tx); + return tx.add(account.generateAuth({ package: this.#accountPackageId })); + }; + + /** Create the sender's canonical account wrapper and share it. One per owner address. */ + createAccount = () => (tx: Transaction) => { + const wrapper = tx.add( + accountRegistry._new({ + package: this.#accountPackageId, + arguments: { registry: this.#config.ids.accountRegistryId }, + }), + ); + tx.add(account.share({ package: this.#accountPackageId, arguments: { self: wrapper } })); + }; + + /** Deposit DUSDC into the account. `amount` is in raw 6-decimal DUSDC units. */ + deposit = (params: { account: string; amount: bigint | number }) => (tx: Transaction) => { + this.#setSender(tx); + const coin = coinWithBalance({ type: this.#config.ids.dusdcType, balance: params.amount }); + this.#depositCoin(tx, params.account, coin); + }; + + /** Deposit an already-constructed `Coin` into the account. */ + depositFunds = + (params: { account: string; coin: TransactionObjectArgument }) => (tx: Transaction) => { + this.#setSender(tx); + this.#depositCoin(tx, params.account, params.coin); + }; + + #depositCoin(tx: Transaction, wrapper: string, coin: TransactionObjectArgument) { + const auth = tx.add(account.generateAuth({ package: this.#accountPackageId })); + tx.add( + account.depositFunds({ + package: this.#accountPackageId, + arguments: { wrapper, auth, coin, root: ACCUMULATOR_ROOT_ID }, + typeArguments: [this.#config.ids.dusdcType], + }), + ); + } + + /** + * Withdraw DUSDC from the account. Returns the `Coin`; if `recipient` is set + * it is transferred there, otherwise use the returned coin downstream in the PTB. + */ + withdraw = + (params: { account: string; amount: bigint | number; recipient?: string }) => + (tx: Transaction) => { + this.#setSender(tx); + const auth = tx.add(account.generateAuth({ package: this.#accountPackageId })); + const coin = tx.add( + account.withdrawFunds({ + package: this.#accountPackageId, + arguments: { + wrapper: params.account, + auth, + amount: params.amount, + root: ACCUMULATOR_ROOT_ID, + }, + typeArguments: [this.#config.ids.dusdcType], + }), + ); + if (params.recipient) { + tx.transferObjects([coin], params.recipient); + } + return coin; + }; +} diff --git a/packages/deepbook-predict/src/transactions/flush.ts b/packages/deepbook-predict/src/transactions/flush.ts new file mode 100644 index 000000000..6690a965d --- /dev/null +++ b/packages/deepbook-predict/src/transactions/flush.ts @@ -0,0 +1,127 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import type { Transaction, TransactionArgument } from '@mysten/sui/transactions'; + +import * as plp from '../contracts/deepbook_predict/plp.js'; +import * as registry from '../contracts/deepbook_predict/registry.js'; +import type { PredictConfig } from '../utils/config.js'; +import type { PricerFeeds } from './trade.js'; + +/** + * Keeper flush over `plp` — the pool valuation + LP-queue drain. + * + * The flush is one PTB threading two abilityless hot potatoes: `MarketLifecycleProof` + * (proves an allowlisted `MarketLifecycleCap`) and `PoolValuation`. Use {@link + * FlushContract.fullFlush} to build the whole `generateLifecycleProof → + * startPoolValuation → valueExpiry (per active market) → finishFlush` sequence; the + * primitives are exposed for custom composition. Every active market from + * `plp::active_expiry_markets(vault)` must be valued exactly once or `finishFlush` + * aborts, and `valueExpiry` builds its own pricer, so each entry needs the market's + * four propbook feeds. + */ +export class FlushContract { + #config: PredictConfig; + + constructor(config: PredictConfig) { + this.#config = config; + } + + get #predictPackageId() { + return this.#config.ids.predictPackageId; + } + + /** Mint a `MarketLifecycleProof` from an allowlisted `MarketLifecycleCap`. */ + generateLifecycleProof = (params: { lifecycleCap: string }) => (tx: Transaction) => + tx.add( + registry.generateLifecycleProof({ + package: this.#predictPackageId, + arguments: { registry: this.#config.ids.registryId, lifecycleCap: params.lifecycleCap }, + }), + ); + + /** Consume the proof, engage the valuation lock, snapshot active markets; returns `PoolValuation`. */ + startPoolValuation = (params: { proof: TransactionArgument }) => (tx: Transaction) => + tx.add( + plp.startPoolValuation({ + package: this.#predictPackageId, + arguments: { + config: this.#config.ids.protocolConfigId, + vault: this.#config.ids.poolVaultId, + lifecycleProof: params.proof, + }, + }), + ); + + /** Fold one market's NAV into the valuation (builds its pricer from the market's feeds). */ + valueExpiry = + (params: { valuation: TransactionArgument; market: string; feeds: PricerFeeds }) => + (tx: Transaction) => + tx.add( + plp.valueExpiry({ + package: this.#predictPackageId, + arguments: { + valuation: params.valuation, + vault: this.#config.ids.poolVaultId, + market: params.market, + config: this.#config.ids.protocolConfigId, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.feeds.pyth, + bsSpot: params.feeds.bsSpot, + bsForward: params.feeds.bsForward, + bsSvi: params.feeds.bsSvi, + }, + }), + ); + + /** + * Consume the valuation, price pool NAV, and drain the LP queues at that mark. + * `supplyBudget`/`withdrawBudget` cap how many requests drain (null = drain fully). + * Returns LP-attributable pool NAV (u64). + */ + finishFlush = + (params: { + valuation: TransactionArgument; + supplyBudget?: bigint | number | null; + withdrawBudget?: bigint | number | null; + }) => + (tx: Transaction) => + tx.add( + plp.finishFlush({ + package: this.#predictPackageId, + arguments: { + valuation: params.valuation, + vault: this.#config.ids.poolVaultId, + config: this.#config.ids.protocolConfigId, + supplyBudget: params.supplyBudget ?? null, + withdrawBudget: params.withdrawBudget ?? null, + }, + }), + ); + + /** + * Build the complete flush in one PTB. `markets` must be every active market + * (read `plp::active_expiry_markets`), each with its four resolved propbook feeds. + */ + fullFlush = + (params: { + lifecycleCap: string; + markets: Array<{ market: string; feeds: PricerFeeds }>; + supplyBudget?: bigint | number | null; + withdrawBudget?: bigint | number | null; + }) => + (tx: Transaction) => { + const proof = tx.add(this.generateLifecycleProof({ lifecycleCap: params.lifecycleCap })); + const valuation = tx.add(this.startPoolValuation({ proof })); + for (const m of params.markets) { + tx.add(this.valueExpiry({ valuation, market: m.market, feeds: m.feeds })); + } + return tx.add( + this.finishFlush({ + valuation, + supplyBudget: params.supplyBudget, + withdrawBudget: params.withdrawBudget, + }), + ); + }; +} diff --git a/packages/deepbook-predict/src/transactions/lp.test.ts b/packages/deepbook-predict/src/transactions/lp.test.ts new file mode 100644 index 000000000..0efc5d554 --- /dev/null +++ b/packages/deepbook-predict/src/transactions/lp.test.ts @@ -0,0 +1,98 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { Transaction } from '@mysten/sui/transactions'; +import { describe, expect, it } from 'vitest'; + +import { PredictConfig } from '../utils/config.js'; +import type { PredictIds } from '../utils/config.js'; +import { FlushContract } from './flush.js'; +import { LpContract } from './lp.js'; +import type { PricerFeeds } from './trade.js'; + +const A = (n: number) => `0x${n.toString(16).padStart(64, '0')}`; +const IDS: PredictIds = { + predictPackageId: A(0x101), + accountPackageId: A(0x102), + propbookPackageId: A(0x103), + registryId: A(0x104), + poolVaultId: A(0x105), + protocolConfigId: A(0x106), + oracleRegistryId: A(0x107), + accountRegistryId: A(0x108), + dusdcType: `${A(0x109)}::dusdc::DUSDC`, +}; +const ACCOUNT = A(0x201); +const feeds = (n: number): PricerFeeds => ({ + pyth: A(n), + bsSpot: A(n + 1), + bsForward: A(n + 2), + bsSvi: A(n + 3), +}); + +const config = new PredictConfig({ network: 'testnet', address: A(0xa11ce), ids: IDS }); +const lp = new LpContract(config); +const flush = new FlushContract(config); + +function targets(tx: Transaction): string[] { + const commands = ( + tx.getData() as { commands: Array<{ MoveCall?: { module: string; function: string } }> } + ).commands; + return commands.flatMap((c) => + c.MoveCall ? [`${c.MoveCall.module}::${c.MoveCall.function}`] : [], + ); +} + +describe('LP builders', () => { + it('requestSupply → owner auth + request_supply', () => { + const tx = new Transaction(); + tx.add(lp.requestSupply({ account: ACCOUNT, amount: 10_000_000n })); + expect(targets(tx)).toEqual(['account::generate_auth', 'plp::request_supply']); + }); + + it('stakeDeep → owner auth + stake_deep', () => { + const tx = new Transaction(); + tx.add(lp.stakeDeep({ account: ACCOUNT, amount: 1_000_000n })); + expect(targets(tx)).toEqual(['account::generate_auth', 'plp::stake_deep']); + }); + + it('sponsorFeeIncentives → sponsor_fee_incentives (permissionless, no auth)', () => { + const tx = new Transaction(); + tx.add(lp.sponsorFeeIncentives({ amount: 10_000_000n })); + expect(targets(tx)).toEqual(['plp::sponsor_fee_incentives']); + }); + + it('rebalanceExpiryCash → rebalance_expiry_cash (permissionless)', () => { + const tx = new Transaction(); + tx.add(lp.rebalanceExpiryCash({ market: A(0x202), pyth: A(0x301) })); + expect(targets(tx)).toEqual(['plp::rebalance_expiry_cash']); + }); + + it('lockCapital → lock_capital (admin)', () => { + const tx = new Transaction(); + tx.add(lp.lockCapital({ adminCap: A(0x501), amount: 10_000_000n })); + expect(targets(tx)).toEqual(['plp::lock_capital']); + }); +}); + +describe('flush builder', () => { + it('fullFlush composes the hot-potato sequence for every market', () => { + const tx = new Transaction(); + tx.add( + flush.fullFlush({ + lifecycleCap: A(0x601), + markets: [ + { market: A(0x701), feeds: feeds(0x800) }, + { market: A(0x702), feeds: feeds(0x900) }, + ], + }), + ); + expect(targets(tx)).toEqual([ + 'registry::generate_lifecycle_proof', + 'plp::start_pool_valuation', + 'plp::value_expiry', + 'plp::value_expiry', + 'plp::finish_flush', + ]); + }); +}); diff --git a/packages/deepbook-predict/src/transactions/lp.ts b/packages/deepbook-predict/src/transactions/lp.ts new file mode 100644 index 000000000..30627555f --- /dev/null +++ b/packages/deepbook-predict/src/transactions/lp.ts @@ -0,0 +1,240 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { coinWithBalance } from '@mysten/sui/transactions'; +import type { Transaction } from '@mysten/sui/transactions'; + +import * as account from '../contracts/account/account.js'; +import * as plp from '../contracts/deepbook_predict/plp.js'; +import type { PredictConfig } from '../utils/config.js'; +import { ACCUMULATOR_ROOT_ID } from '../utils/constants.js'; + +/** + * Liquidity-provider flows over `plp` (the shared `PoolVault`). + * + * Supply/withdraw are asynchronous: `requestSupply`/`requestWithdraw` escrow funds + * from the account and return a queue index (readable from the emitted event / tx + * effects) that `cancel*` uses; the request is filled at the next keeper flush. + * DUSDC/DEEP/PLP amounts are pulled from the account internally (no coin arg) except + * `sponsorFeeIncentives`/`lockCapital`, which take an actual `Coin`. Owner + * flows mint a fresh `Auth`; `Clock` is auto-injected; `AccumulatorRoot` is `0xacc`. + */ +export class LpContract { + #config: PredictConfig; + + constructor(config: PredictConfig) { + this.#config = config; + } + + get #predictPackageId() { + return this.#config.ids.predictPackageId; + } + + get #vault() { + return this.#config.ids.poolVaultId; + } + + get #protocolConfig() { + return this.#config.ids.protocolConfigId; + } + + #auth(tx: Transaction) { + if (this.#config.address) { + tx.setSenderIfNotSet(this.#config.address); + } + return tx.add(account.generateAuth({ package: this.#config.ids.accountPackageId })); + } + + /** Queue a DUSDC supply (`amount` raw DUSDC). Returns the queue index (u64) as a tx result. */ + requestSupply = (params: { account: string; amount: bigint | number }) => (tx: Transaction) => { + const auth = this.#auth(tx); + return tx.add( + plp.requestSupply({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + wrapper: params.account, + auth, + config: this.#protocolConfig, + amount: params.amount, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Queue a PLP-share withdraw (`amount` raw PLP shares). Returns the queue index (u64). */ + requestWithdraw = (params: { account: string; amount: bigint | number }) => (tx: Transaction) => { + const auth = this.#auth(tx); + return tx.add( + plp.requestWithdraw({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + wrapper: params.account, + auth, + config: this.#protocolConfig, + amount: params.amount, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Cancel a pending supply request by queue index; refunds escrowed DUSDC to the account. */ + cancelSupplyRequest = + (params: { account: string; index: bigint | number }) => (tx: Transaction) => { + const auth = this.#auth(tx); + tx.add( + plp.cancelSupplyRequest({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + wrapper: params.account, + auth, + config: this.#protocolConfig, + index: params.index, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Cancel a pending withdraw request by queue index; refunds escrowed PLP to the account. */ + cancelWithdrawRequest = + (params: { account: string; index: bigint | number }) => (tx: Transaction) => { + const auth = this.#auth(tx); + tx.add( + plp.cancelWithdrawRequest({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + wrapper: params.account, + auth, + config: this.#protocolConfig, + index: params.index, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Stake DEEP (pulled from the account) for trading-fee benefits; activates next epoch. */ + stakeDeep = (params: { account: string; amount: bigint | number }) => (tx: Transaction) => { + const auth = this.#auth(tx); + tx.add( + plp.stakeDeep({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + wrapper: params.account, + auth, + config: this.#protocolConfig, + amount: params.amount, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Unstake all DEEP back to the account (no penalty). */ + unstakeDeep = (params: { account: string }) => (tx: Transaction) => { + const auth = this.#auth(tx); + tx.add( + plp.unstakeDeep({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + wrapper: params.account, + auth, + config: this.#protocolConfig, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Claim the account's settled trading-loss rebate for a market (owner auth). Needs the market's Pyth feed. */ + claimTradingLossRebate = + (params: { account: string; market: string; pyth: string }) => (tx: Transaction) => { + const auth = this.#auth(tx); + tx.add( + plp.claimTradingLossRebate({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + market: params.market, + wrapper: params.account, + auth, + config: this.#protocolConfig, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.pyth, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Permissionless (keeper) trading-loss rebate claim via app-auth; no owner `Auth`. */ + claimTradingLossRebatePermissionless = + (params: { account: string; market: string; pyth: string }) => (tx: Transaction) => { + tx.add( + plp.claimTradingLossRebatePermissionless({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + market: params.market, + wrapper: params.account, + accountRegistry: this.#config.ids.accountRegistryId, + config: this.#protocolConfig, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.pyth, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** Contribute DUSDC (`amount` raw) to the pool fee-incentive reserve. Permissionless. */ + sponsorFeeIncentives = (params: { amount: bigint | number }) => (tx: Transaction) => { + const payment = coinWithBalance({ type: this.#config.ids.dusdcType, balance: params.amount }); + tx.add( + plp.sponsorFeeIncentives({ + package: this.#predictPackageId, + arguments: { vault: this.#vault, config: this.#protocolConfig, payment }, + }), + ); + }; + + /** Permissionless per-market cash rebalance; makes a market mintable. Needs the market's Pyth feed. */ + rebalanceExpiryCash = (params: { market: string; pyth: string }) => (tx: Transaction) => { + tx.add( + plp.rebalanceExpiryCash({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + market: params.market, + config: this.#protocolConfig, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.pyth, + }, + }), + ); + }; + + /** One-time admin bootstrap: permanently lock genesis DUSDC liquidity (`amount` raw). */ + lockCapital = (params: { adminCap: string; amount: bigint | number }) => (tx: Transaction) => { + const payment = coinWithBalance({ type: this.#config.ids.dusdcType, balance: params.amount }); + tx.add( + plp.lockCapital({ + package: this.#predictPackageId, + arguments: { + vault: this.#vault, + config: this.#protocolConfig, + AdminCap: params.adminCap, + payment, + }, + }), + ); + }; +} diff --git a/packages/deepbook-predict/src/transactions/predictAccount.ts b/packages/deepbook-predict/src/transactions/predictAccount.ts new file mode 100644 index 000000000..58261eecd --- /dev/null +++ b/packages/deepbook-predict/src/transactions/predictAccount.ts @@ -0,0 +1,52 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import type { Transaction } from '@mysten/sui/transactions'; + +import * as account from '../contracts/account/account.js'; +import * as predictAccount from '../contracts/deepbook_predict/predict_account.js'; +import type { PredictConfig } from '../utils/config.js'; + +/** + * Predict-side account settings stored in the account's `PredictData` slot. + * + * The `PredictData` slot is auto-attached on first mint (or first `set_builder_code`), + * so a trader needs no explicit setup beyond creating + funding the account. Both + * calls consume a fresh owner `Auth`. + */ +export class PredictAccountContract { + #config: PredictConfig; + + constructor(config: PredictConfig) { + this.#config = config; + } + + #auth(tx: Transaction) { + if (this.#config.address) { + tx.setSenderIfNotSet(this.#config.address); + } + return tx.add(account.generateAuth({ package: this.#config.ids.accountPackageId })); + } + + /** Opt into a builder code (`code` is a shared `BuilderCode` object id). */ + setBuilderCode = (params: { account: string; builderCode: string }) => (tx: Transaction) => { + const auth = this.#auth(tx); + tx.add( + predictAccount.setBuilderCode({ + package: this.#config.ids.predictPackageId, + arguments: { wrapper: params.account, auth, code: params.builderCode }, + }), + ); + }; + + /** Clear the account's builder code. */ + unsetBuilderCode = (params: { account: string }) => (tx: Transaction) => { + const auth = this.#auth(tx); + tx.add( + predictAccount.unsetBuilderCode({ + package: this.#config.ids.predictPackageId, + arguments: { wrapper: params.account, auth }, + }), + ); + }; +} diff --git a/packages/deepbook-predict/src/transactions/trade.ts b/packages/deepbook-predict/src/transactions/trade.ts new file mode 100644 index 000000000..6ba3ac34c --- /dev/null +++ b/packages/deepbook-predict/src/transactions/trade.ts @@ -0,0 +1,271 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import type { Transaction, TransactionArgument } from '@mysten/sui/transactions'; + +import * as account from '../contracts/account/account.js'; +import * as expiryMarket from '../contracts/deepbook_predict/expiry_market.js'; +import type { PredictConfig } from '../utils/config.js'; +import { ACCUMULATOR_ROOT_ID, U64_MAX } from '../utils/constants.js'; + +/** + * The four canonical propbook feed object ids for a market's underlying. Resolve them + * from the `OracleRegistry` via `propbook_*_id_for_underlying(market.propbook_underlying_id)` + * (a query helper for this lands in a later milestone); they must be the current + * canonical feeds or `load_live_pricer` aborts. + */ +export interface PricerFeeds { + pyth: string; + bsSpot: string; + bsForward: string; + bsSvi: string; +} + +/** + * Trader flows over `expiry_market`. + * + * Live-priced flows (mint, `redeemLive`, `currentNav`) take a `Pricer` — build it once + * per market per transaction with {@link TradeContract.loadLivePricer} and thread the + * returned value in (it is `copy`/`drop` and bound to that one market). Owner actions + * mint a fresh `Auth` internally. `Clock` is auto-injected; `AccumulatorRoot` (`0xacc`) + * is passed explicitly for the internal DUSDC settle. + */ +export class TradeContract { + #config: PredictConfig; + + constructor(config: PredictConfig) { + this.#config = config; + } + + get #predictPackageId() { + return this.#config.ids.predictPackageId; + } + + #auth(tx: Transaction) { + if (this.#config.address) { + tx.setSenderIfNotSet(this.#config.address); + } + return tx.add(account.generateAuth({ package: this.#config.ids.accountPackageId })); + } + + /** + * Load a live `Pricer` bound to `market`. Returns the pricer to thread into mint / + * `redeemLive` / `currentNav` in the SAME transaction. + */ + loadLivePricer = (params: { market: string; feeds: PricerFeeds }) => (tx: Transaction) => + tx.add( + expiryMarket.loadLivePricer({ + package: this.#predictPackageId, + arguments: { + market: params.market, + config: this.#config.ids.protocolConfigId, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.feeds.pyth, + bsSpot: params.feeds.bsSpot, + bsForward: params.feeds.bsForward, + bsSvi: params.feeds.bsSvi, + }, + }), + ); + + /** + * Mint an exact contract quantity. `quantity` is in quote units (a multiple of the + * position lot size); `leverage` is 1e9-scaled; `maxCost` (all-in DUSDC) and + * `maxProbability` (1e9-scaled) are slippage caps, defaulting to uncapped. Returns + * the minted order id (`u256`) as a transaction result. + */ + mintExactQuantity = + (params: { + market: string; + account: string; + pricer: TransactionArgument; + lowerTick: bigint | number; + higherTick: bigint | number; + quantity: bigint | number; + leverage: bigint | number; + maxCost?: bigint | number; + maxProbability?: bigint | number; + }) => + (tx: Transaction) => { + const auth = this.#auth(tx); + return tx.add( + expiryMarket.mintExactQuantity({ + package: this.#predictPackageId, + arguments: { + market: params.market, + wrapper: params.account, + auth, + config: this.#config.ids.protocolConfigId, + pricer: params.pricer, + lowerTick: params.lowerTick, + higherTick: params.higherTick, + quantity: params.quantity, + leverage: params.leverage, + maxCost: params.maxCost ?? U64_MAX, + maxProbability: params.maxProbability ?? U64_MAX, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** + * Mint as much quantity as `amount` (net-premium budget, raw DUSDC) buys. `minQuantity` + * is the slippage guard; fees/penalty are charged on top of `amount`. Returns the + * minted order id (`u256`). + */ + mintExactAmount = + (params: { + market: string; + account: string; + pricer: TransactionArgument; + lowerTick: bigint | number; + higherTick: bigint | number; + amount: bigint | number; + minQuantity: bigint | number; + leverage: bigint | number; + }) => + (tx: Transaction) => { + const auth = this.#auth(tx); + return tx.add( + expiryMarket.mintExactAmount({ + package: this.#predictPackageId, + arguments: { + market: params.market, + wrapper: params.account, + auth, + config: this.#config.ids.protocolConfigId, + pricer: params.pricer, + lowerTick: params.lowerTick, + higherTick: params.higherTick, + amount: params.amount, + minQuantity: params.minQuantity, + leverage: params.leverage, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** + * Close (fully or partially) a live position. `minProbability` / `minProceeds` + * (default 0 = disabled) are slippage floors. Returns `(closedOrderId, Option)`; + * a partial close yields a `Some` replacement. + */ + redeemLive = + (params: { + market: string; + account: string; + pricer: TransactionArgument; + orderId: bigint | number; + closeQuantity: bigint | number; + minProbability?: bigint | number; + minProceeds?: bigint | number; + }) => + (tx: Transaction) => { + const auth = this.#auth(tx); + return tx.add( + expiryMarket.redeemLive({ + package: this.#predictPackageId, + arguments: { + market: params.market, + wrapper: params.account, + auth, + config: this.#config.ids.protocolConfigId, + pricer: params.pricer, + orderId: params.orderId, + closeQuantity: params.closeQuantity, + minProbability: params.minProbability ?? 0, + minProceeds: params.minProceeds ?? 0, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** + * Redeem a settled position at its terminal payout (owner authority). `closeQuantity` + * must equal the full order quantity. Needs the underlying's Pyth feed for the settled + * spot; no pricer. + */ + redeemSettled = + (params: { + market: string; + account: string; + pyth: string; + orderId: bigint | number; + closeQuantity: bigint | number; + }) => + (tx: Transaction) => { + const auth = this.#auth(tx); + return tx.add( + expiryMarket.redeemSettled({ + package: this.#predictPackageId, + arguments: { + market: params.market, + wrapper: params.account, + auth, + config: this.#config.ids.protocolConfigId, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.pyth, + orderId: params.orderId, + closeQuantity: params.closeQuantity, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + }; + + /** + * Permissionless settled redeem (keeper path) — uses app-auth from the account + * registry instead of owner `Auth`. Aborts if `PredictApp` has been deauthorized. + */ + redeemSettledPermissionless = + (params: { + market: string; + account: string; + pyth: string; + orderId: bigint | number; + closeQuantity: bigint | number; + }) => + (tx: Transaction) => + tx.add( + expiryMarket.redeemSettledPermissionless({ + package: this.#predictPackageId, + arguments: { + market: params.market, + accountRegistry: this.#config.ids.accountRegistryId, + wrapper: params.account, + config: this.#config.ids.protocolConfigId, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.pyth, + orderId: params.orderId, + closeQuantity: params.closeQuantity, + root: ACCUMULATOR_ROOT_ID, + }, + }), + ); + + /** Exact live NAV of a market (read; use with `devInspect`). Requires a market-bound pricer. */ + currentNav = (params: { market: string; pricer: TransactionArgument }) => (tx: Transaction) => + tx.add( + expiryMarket.currentNav({ + package: this.#predictPackageId, + arguments: { market: params.market, pricer: params.pricer }, + }), + ); + + /** Set the market's reference tick from the underlying's current Pyth spot. */ + setReferenceTick = (params: { market: string; pyth: string }) => (tx: Transaction) => + tx.add( + expiryMarket.setReferenceTick({ + package: this.#predictPackageId, + arguments: { + market: params.market, + config: this.#config.ids.protocolConfigId, + propbookRegistry: this.#config.ids.oracleRegistryId, + pyth: params.pyth, + }, + }), + ); +} diff --git a/packages/deepbook-predict/src/transactions/transactions.test.ts b/packages/deepbook-predict/src/transactions/transactions.test.ts new file mode 100644 index 000000000..99874d25a --- /dev/null +++ b/packages/deepbook-predict/src/transactions/transactions.test.ts @@ -0,0 +1,174 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { Transaction } from '@mysten/sui/transactions'; +import { describe, expect, it } from 'vitest'; + +import { encodeOrderId } from '../types/orderId.js'; +import { PredictConfig } from '../utils/config.js'; +import type { PredictIds } from '../utils/config.js'; +import { FLOAT_SCALING } from '../utils/constants.js'; +import { AccountContract } from './account.js'; +import { PredictAccountContract } from './predictAccount.js'; +import type { PricerFeeds } from './trade.js'; +import { TradeContract } from './trade.js'; + +// Deterministic dummy ids so the built PTB is fully offline-inspectable. +const A = (n: number) => `0x${n.toString(16).padStart(64, '0')}`; +const IDS: PredictIds = { + predictPackageId: A(0x101), + accountPackageId: A(0x102), + propbookPackageId: A(0x103), + registryId: A(0x104), + poolVaultId: A(0x105), + protocolConfigId: A(0x106), + oracleRegistryId: A(0x107), + accountRegistryId: A(0x108), + dusdcType: `${A(0x109)}::dusdc::DUSDC`, +}; +const ACCOUNT = A(0x201); +const MARKET = A(0x202); +const FEEDS: PricerFeeds = { + pyth: A(0x301), + bsSpot: A(0x302), + bsForward: A(0x303), + bsSvi: A(0x304), +}; + +const config = new PredictConfig({ network: 'testnet', address: A(0xa11ce), ids: IDS }); +const acct = new AccountContract(config); +const predictAcct = new PredictAccountContract(config); +const trade = new TradeContract(config); + +/** Ordered `module::function` targets of the MoveCall commands in a transaction. */ +function targets(tx: Transaction): string[] { + const commands = ( + tx.getData() as { commands: Array<{ MoveCall?: { module: string; function: string } }> } + ).commands; + return commands.flatMap((c) => + c.MoveCall ? [`${c.MoveCall.module}::${c.MoveCall.function}`] : [], + ); +} + +/** The `package` of the first MoveCall matching `module::function`. */ +function packageOf(tx: Transaction, target: string): string | undefined { + const commands = ( + tx.getData() as { + commands: Array<{ MoveCall?: { package: string; module: string; function: string } }>; + } + ).commands; + const mc = commands.find( + (c) => c.MoveCall && `${c.MoveCall.module}::${c.MoveCall.function}` === target, + ); + return mc?.MoveCall?.package; +} + +describe('account custody builders', () => { + it('createAccount → registry new + share', () => { + const tx = new Transaction(); + tx.add(acct.createAccount()); + expect(targets(tx)).toEqual(['account_registry::new', 'account::share']); + expect(packageOf(tx, 'account_registry::new')).toBe(IDS.accountPackageId); + }); + + it('deposit → generate_auth + deposit_funds', () => { + const tx = new Transaction(); + tx.add(acct.deposit({ account: ACCOUNT, amount: 1_000_000n })); + expect(targets(tx)).toContain('account::generate_auth'); + expect(targets(tx)).toContain('account::deposit_funds'); + }); + + it('withdraw → generate_auth + withdraw_funds, transfers when recipient set', () => { + const tx = new Transaction(); + tx.add(acct.withdraw({ account: ACCOUNT, amount: 500_000n, recipient: A(0xbeef) })); + expect(targets(tx)).toEqual(['account::generate_auth', 'account::withdraw_funds']); + }); +}); + +describe('trade builders', () => { + it('loadLivePricer → expiry_market::load_live_pricer on the predict package', () => { + const tx = new Transaction(); + tx.add(trade.loadLivePricer({ market: MARKET, feeds: FEEDS })); + expect(targets(tx)).toEqual(['expiry_market::load_live_pricer']); + expect(packageOf(tx, 'expiry_market::load_live_pricer')).toBe(IDS.predictPackageId); + }); + + it('mintExactQuantity → pricer load, owner auth, then mint', () => { + const tx = new Transaction(); + const pricer = tx.add(trade.loadLivePricer({ market: MARKET, feeds: FEEDS })); + tx.add( + trade.mintExactQuantity({ + market: MARKET, + account: ACCOUNT, + pricer, + lowerTick: 1n, + higherTick: 2n, + quantity: 10_000n, + leverage: FLOAT_SCALING, + }), + ); + expect(targets(tx)).toEqual([ + 'expiry_market::load_live_pricer', + 'account::generate_auth', + 'expiry_market::mint_exact_quantity', + ]); + }); + + it('redeemLive accepts a codec-produced order id', () => { + const tx = new Transaction(); + const pricer = tx.add(trade.loadLivePricer({ market: MARKET, feeds: FEEDS })); + const orderId = encodeOrderId({ + lowerTick: 1n, + higherTick: 2n, + floorShares: 0n, + quantity: 10_000n, + sequence: 1n, + }); + tx.add( + trade.redeemLive({ + market: MARKET, + account: ACCOUNT, + pricer, + orderId, + closeQuantity: 10_000n, + }), + ); + expect(targets(tx)).toContain('expiry_market::redeem_live'); + }); + + it('redeemSettled uses owner auth + pyth (no pricer)', () => { + const tx = new Transaction(); + tx.add( + trade.redeemSettled({ + market: MARKET, + account: ACCOUNT, + pyth: FEEDS.pyth, + orderId: 1n, + closeQuantity: 10_000n, + }), + ); + expect(targets(tx)).toEqual(['account::generate_auth', 'expiry_market::redeem_settled']); + }); + + it('redeemSettledPermissionless takes no auth', () => { + const tx = new Transaction(); + tx.add( + trade.redeemSettledPermissionless({ + market: MARKET, + account: ACCOUNT, + pyth: FEEDS.pyth, + orderId: 1n, + closeQuantity: 10_000n, + }), + ); + expect(targets(tx)).toEqual(['expiry_market::redeem_settled_permissionless']); + }); +}); + +describe('predict account builders', () => { + it('setBuilderCode → owner auth + set_builder_code', () => { + const tx = new Transaction(); + tx.add(predictAcct.setBuilderCode({ account: ACCOUNT, builderCode: A(0x401) })); + expect(targets(tx)).toEqual(['account::generate_auth', 'predict_account::set_builder_code']); + }); +}); diff --git a/packages/deepbook-predict/src/types/orderId.test.ts b/packages/deepbook-predict/src/types/orderId.test.ts new file mode 100644 index 000000000..3a72599e4 --- /dev/null +++ b/packages/deepbook-predict/src/types/orderId.test.ts @@ -0,0 +1,165 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it } from 'vitest'; + +import { POS_INF_TICK, POSITION_LOT_SIZE } from '../utils/constants.js'; +import { decodeOrderId, encodeOrderId, quantityToLots } from './orderId.js'; + +const U32_MASK = (1n << 32n) - 1n; +const U64_MASK = (1n << 64n) - 1n; + +// Independent oracle: pack via multiplication/addition (2**offset) rather than the +// codec's shift/OR. Agreement pins both the bit offsets and the complement scheme +// against `deepbook_predict::order`, so a wrong-but-round-trip-consistent offset +// is still caught. +function packReference(t: { + lowerTick: bigint; + higherTick: bigint; + floorShares: bigint; + quantity: bigint; + sequence: bigint; +}): bigint { + const lots = t.quantity / POSITION_LOT_SIZE; + const quantityLotsKey = U32_MASK - lots; + const floorSharesKey = U64_MASK - t.floorShares; + return ( + quantityLotsKey * 2n ** 164n + + floorSharesKey * 2n ** 100n + + t.lowerTick * 2n ** 70n + + t.higherTick * 2n ** 40n + + t.sequence + ); +} + +const CASES = [ + { lowerTick: 0n, higherTick: 5n, floorShares: 0n, quantity: 20_000n, sequence: 7n }, + { lowerTick: 1n, higherTick: POS_INF_TICK, floorShares: 0n, quantity: 10_000n, sequence: 0n }, + { lowerTick: 100n, higherTick: 200n, floorShares: 40_000n, quantity: 50_000n, sequence: 12345n }, + { + lowerTick: POS_INF_TICK - 1n, + higherTick: POS_INF_TICK, + floorShares: 10_000n, + quantity: 10_000n, + sequence: (1n << 40n) - 1n, + }, +]; + +describe('order-id codec', () => { + it('matches the independent reference packing', () => { + for (const c of CASES) { + expect(encodeOrderId(c)).toBe(packReference(c)); + } + }); + + it('round-trips encode -> decode', () => { + for (const c of CASES) { + const decoded = decodeOrderId(encodeOrderId(c)); + expect(decoded.lowerTick).toBe(c.lowerTick); + expect(decoded.higherTick).toBe(c.higherTick); + expect(decoded.floorShares).toBe(c.floorShares); + expect(decoded.quantity).toBe(c.quantity); + expect(decoded.sequence).toBe(c.sequence); + expect(decoded.quantityLots).toBe(c.quantity / POSITION_LOT_SIZE); + expect(decoded.isLeveraged).toBe(c.floorShares > 0n); + expect(decoded.orderId >> 196n).toBe(0n); + } + }); + + it('isolates fields — changing one input changes only that decoded field', () => { + const base = { + lowerTick: 10n, + higherTick: 20n, + floorShares: 0n, + quantity: 30_000n, + sequence: 1n, + }; + const bumped = decodeOrderId(encodeOrderId({ ...base, sequence: 2n })); + const baseDecoded = decodeOrderId(encodeOrderId(base)); + expect(bumped.sequence).toBe(2n); + expect(bumped.lowerTick).toBe(baseDecoded.lowerTick); + expect(bumped.higherTick).toBe(baseDecoded.higherTick); + expect(bumped.quantity).toBe(baseDecoded.quantity); + }); + + it('accepts number and string inputs', () => { + const fromBig = encodeOrderId({ + lowerTick: 3n, + higherTick: 9n, + floorShares: 0n, + quantity: 10_000n, + sequence: 4n, + }); + expect( + encodeOrderId({ lowerTick: 3, higherTick: 9, floorShares: 0, quantity: 10_000, sequence: 4 }), + ).toBe(fromBig); + expect(decodeOrderId(fromBig.toString()).orderId).toBe(fromBig); + }); + + describe('rejections', () => { + it('rejects the (neg_inf, pos_inf) range', () => { + expect(() => + encodeOrderId({ + lowerTick: 0n, + higherTick: POS_INF_TICK, + floorShares: 0n, + quantity: 10_000n, + sequence: 0n, + }), + ).toThrow(); + }); + + it('rejects lowerTick >= higherTick', () => { + expect(() => + encodeOrderId({ + lowerTick: 5n, + higherTick: 5n, + floorShares: 0n, + quantity: 10_000n, + sequence: 0n, + }), + ).toThrow(); + }); + + it('rejects a tick above POS_INF_TICK', () => { + expect(() => + encodeOrderId({ + lowerTick: 1n, + higherTick: POS_INF_TICK + 1n, + floorShares: 0n, + quantity: 10_000n, + sequence: 0n, + }), + ).toThrow(); + }); + + it('rejects a quantity that is not a whole lot', () => { + expect(() => quantityToLots(15_000n)).toThrow(); + expect(() => + encodeOrderId({ + lowerTick: 1n, + higherTick: 2n, + floorShares: 0n, + quantity: 15_000n, + sequence: 0n, + }), + ).toThrow(); + }); + + it('rejects floorShares > quantity', () => { + expect(() => + encodeOrderId({ + lowerTick: 1n, + higherTick: 2n, + floorShares: 20_000n, + quantity: 10_000n, + sequence: 0n, + }), + ).toThrow(); + }); + + it('rejects an ID with bits set above 196', () => { + expect(() => decodeOrderId(1n << 196n)).toThrow(); + }); + }); +}); diff --git a/packages/deepbook-predict/src/types/orderId.ts b/packages/deepbook-predict/src/types/orderId.ts new file mode 100644 index 000000000..4ab8bfa34 --- /dev/null +++ b/packages/deepbook-predict/src/types/orderId.ts @@ -0,0 +1,160 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { POS_INF_TICK, POSITION_LOT_SIZE } from '../utils/constants.js'; + +/** + * Order-ID codec — TypeScript mirror of `deepbook_predict::order`. + * + * A Predict order ID is a packed `u256` (196 significant bits). The Move module + * exposes no public accessors, so the SDK replicates the packing to read and + * construct order IDs. Layout (bit 0 = least significant): + * + * ``` + * sequence : bits 0..39 (40 bits) + * higher_tick : bits 40..69 (30 bits) + * lower_tick : bits 70..99 (30 bits) + * floor_shares : bits 100..163 (64 bits, stored as U64_MASK - floor_shares) + * quantity_lots : bits 164..195 (32 bits, stored as U32_MASK - quantity_lots) + * ``` + * + * `quantity = quantity_lots * POSITION_LOT_SIZE`. Lower tick `0` is the + * negative-infinity sentinel; higher tick `POS_INF_TICK` is the positive-infinity + * sentinel. The two complemented fields (`quantity_lots`, `floor_shares`) preserve + * a price-time-like ordering on the raw ID. + */ + +const QUANTITY_LOTS_OFFSET = 164n; +const FLOOR_SHARES_OFFSET = 100n; +const LOWER_TICK_OFFSET = 70n; +const HIGHER_TICK_OFFSET = 40n; +const ORDER_ID_BITS = 196n; + +const TICK_MASK = (1n << 30n) - 1n; +const U32_MASK = (1n << 32n) - 1n; +const U40_MASK = (1n << 40n) - 1n; +const U64_MASK = (1n << 64n) - 1n; + +/** Immutable contract terms encoded in an order ID. */ +export interface OrderTerms { + /** Lower strike tick; `0` (`NEG_INF_TICK`) is the negative-infinity sentinel. */ + lowerTick: bigint; + /** Higher strike tick; `POS_INF_TICK` is the positive-infinity sentinel. */ + higherTick: bigint; + /** Static floor `F` (payout primitive, in quote units); `0` = unleveraged. */ + floorShares: bigint; + /** User-facing quantity; a positive multiple of `POSITION_LOT_SIZE`. */ + quantity: bigint; + /** Expiry-local sequence. */ + sequence: bigint; +} + +/** Decoded view of a packed order ID. */ +export interface DecodedOrder extends OrderTerms { + /** The canonical packed order ID. */ + orderId: bigint; + /** Encoded quantity in position lots (`quantity / POSITION_LOT_SIZE`). */ + quantityLots: bigint; + /** Whether the order carries a non-zero static floor. */ + isLeveraged: boolean; +} + +type BigIntish = bigint | number | string; + +function toBig(value: BigIntish): bigint { + return typeof value === 'bigint' ? value : BigInt(value); +} + +function assertShape(lowerTick: bigint, higherTick: bigint): void { + if (lowerTick > POS_INF_TICK || higherTick > POS_INF_TICK) { + throw new RangeError(`order tick out of range (max ${POS_INF_TICK})`); + } + if (lowerTick >= higherTick) { + throw new RangeError('order requires lowerTick < higherTick'); + } + if (lowerTick === 0n && higherTick === POS_INF_TICK) { + throw new RangeError('order range cannot be (neg_inf, pos_inf)'); + } +} + +/** Convert a user-facing quantity to position lots, validating the increment. */ +export function quantityToLots(quantity: BigIntish): bigint { + const q = toBig(quantity); + if (q <= 0n || q % POSITION_LOT_SIZE !== 0n) { + throw new RangeError(`quantity must be a positive multiple of ${POSITION_LOT_SIZE}`); + } + const lots = q / POSITION_LOT_SIZE; + if (lots > U32_MASK) { + throw new RangeError('quantity exceeds max encodable lots'); + } + return lots; +} + +/** Pack validated contract terms into a canonical order ID. */ +export function encodeOrderId(terms: { + lowerTick: BigIntish; + higherTick: BigIntish; + floorShares: BigIntish; + quantity: BigIntish; + sequence: BigIntish; +}): bigint { + const lowerTick = toBig(terms.lowerTick); + const higherTick = toBig(terms.higherTick); + const floorShares = toBig(terms.floorShares); + const quantity = toBig(terms.quantity); + const sequence = toBig(terms.sequence); + + const quantityLots = quantityToLots(quantity); + if (sequence < 0n || sequence > U40_MASK) { + throw new RangeError('sequence out of range'); + } + if (floorShares < 0n || floorShares > quantity) { + throw new RangeError('floorShares must satisfy 0 <= F <= quantity'); + } + assertShape(lowerTick, higherTick); + + const quantityLotsKey = U32_MASK - quantityLots; + const floorSharesKey = U64_MASK - floorShares; + + return ( + (quantityLotsKey << QUANTITY_LOTS_OFFSET) | + (floorSharesKey << FLOOR_SHARES_OFFSET) | + (lowerTick << LOWER_TICK_OFFSET) | + (higherTick << HIGHER_TICK_OFFSET) | + sequence + ); +} + +/** Decode and validate a packed order ID into its contract terms. */ +export function decodeOrderId(orderId: BigIntish): DecodedOrder { + const id = toBig(orderId); + if (id < 0n || id >> ORDER_ID_BITS !== 0n) { + throw new RangeError('invalid order ID: bits set above the 196-bit field'); + } + + const quantityLots = U32_MASK - ((id >> QUANTITY_LOTS_OFFSET) & U32_MASK); + if (quantityLots === 0n) { + throw new RangeError('invalid order ID: zero quantity'); + } + const floorShares = U64_MASK - ((id >> FLOOR_SHARES_OFFSET) & U64_MASK); + const lowerTick = (id >> LOWER_TICK_OFFSET) & TICK_MASK; + const higherTick = (id >> HIGHER_TICK_OFFSET) & TICK_MASK; + const sequence = id & U40_MASK; + const quantity = quantityLots * POSITION_LOT_SIZE; + + if (floorShares > quantity) { + throw new RangeError('invalid order ID: floorShares exceeds quantity'); + } + assertShape(lowerTick, higherTick); + + return { + orderId: id, + lowerTick, + higherTick, + floorShares, + quantity, + quantityLots, + sequence, + isLeveraged: floorShares > 0n, + }; +} diff --git a/packages/deepbook-predict/src/utils/config.ts b/packages/deepbook-predict/src/utils/config.ts new file mode 100644 index 000000000..87e377290 --- /dev/null +++ b/packages/deepbook-predict/src/utils/config.ts @@ -0,0 +1,71 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// PredictConfig — resolves the package IDs, shared-object IDs, and coin types the +// transaction/query layers need. Predict is not yet published, so there is no +// per-network default block: callers must supply `packageIds` explicitly (the same +// override path deepbook-v3 uses pre-publish). Once Predict deploys, add a +// `TESTNET_PREDICT_IDS` constant here and merge it by `network`. + +export type PredictNetwork = 'mainnet' | 'testnet' | 'localnet'; + +/** On-chain identifiers the SDK resolves calls against. */ +export interface PredictIds { + /** Published `deepbook_predict` package ID (`0x…::module::fn` target prefix). */ + predictPackageId: string; + /** Published `account` package ID (custody primitive). */ + accountPackageId: string; + /** Published `propbook` package ID (oracle feeds). */ + propbookPackageId: string; + /** Shared `deepbook_predict::registry::Registry`. */ + registryId: string; + /** Shared `deepbook_predict::plp::PoolVault`. */ + poolVaultId: string; + /** Shared `deepbook_predict::protocol_config::ProtocolConfig`. */ + protocolConfigId: string; + /** Shared `propbook::registry::OracleRegistry`. */ + oracleRegistryId: string; + /** Shared `account::account_registry::AccountRegistry`. */ + accountRegistryId: string; + /** Fully-qualified DUSDC coin type (the settlement asset). */ + dusdcType: string; +} + +export interface PredictConfigOptions { + network?: PredictNetwork; + /** Default sender address for built transactions. */ + address?: string; + /** + * Base URL of a `predict-server` indexer instance for history/list queries. + * No hosted default exists yet; on-chain (`devInspect`) queries work without it. + */ + indexerUrl?: string; + /** Explicit on-chain IDs. Required until Predict is published. */ + ids: PredictIds; +} + +export class PredictConfig { + readonly network: PredictNetwork; + readonly address?: string; + readonly indexerUrl?: string; + readonly #ids: PredictIds; + + constructor(options: PredictConfigOptions) { + this.network = options.network ?? 'testnet'; + this.address = options.address; + this.indexerUrl = options.indexerUrl; + this.#ids = options.ids; + } + + get ids(): PredictIds { + return this.#ids; + } + + /** Assert an indexer URL is configured, returning it (for indexer-backed queries). */ + requireIndexerUrl(): string { + if (!this.indexerUrl) { + throw new Error('PredictConfig.indexerUrl is not set; this query requires an indexer'); + } + return this.indexerUrl; + } +} diff --git a/packages/deepbook-predict/src/utils/constants.ts b/packages/deepbook-predict/src/utils/constants.ts new file mode 100644 index 000000000..cdbc9b185 --- /dev/null +++ b/packages/deepbook-predict/src/utils/constants.ts @@ -0,0 +1,43 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Protocol constants mirrored from `deepbook_predict::constants` (Move source is +// the source of truth). Values that interact with the packed-u256 order ID are +// `bigint`; plain decimal-scaling metadata is `number`. + +/** Fixed-point scaling for prices/probabilities/percentages (1e9). */ +export const FLOAT_SCALING = 1_000_000_000n; +/** Decimal exponent of `FLOAT_SCALING` (i.e. 1e9). */ +export const FLOAT_SCALING_DECIMALS = 9; + +/** Decimals of the DUSDC settlement asset (the pool's denomination). */ +export const DUSDC_DECIMALS = 6; +/** Decimals of DEEP (used for LP staking). */ +export const DEEP_DECIMALS = 6; + +/** Minimum position quantity increment (`1_000_000` quote units = 1 contract). */ +export const POSITION_LOT_SIZE = 10_000n; +/** Minimum mint-time net premium, excluding trading and builder fees. */ +export const MIN_NET_PREMIUM = 1_000_000n; + +/** Bit width of each strike tick field packed into an order ID. */ +export const TICK_BITS = 30n; +/** + * Positive-infinity sentinel tick and maximum finite-tick bound. As the higher + * tick it is the open upper bound; finite ticks occupy `1..POS_INF_TICK - 1`, and + * tick `0` is the negative-infinity sentinel as the lower tick. + */ +export const POS_INF_TICK = (1n << TICK_BITS) - 1n; +/** Negative-infinity sentinel lower tick. */ +export const NEG_INF_TICK = 0n; +/** Granularity unit for market tick sizes; every tick_size is a multiple of this. */ +export const MARKET_TICK_SIZE_UNIT = 10_000n; + +/** `u64::MAX` — the sentinel for "uncapped" mint slippage guards (max_cost / max_probability). */ +export const U64_MAX = (1n << 64n) - 1n; + +/** + * The Sui system `AccumulatorRoot` shared object, at the reserved address `0xacc` on + * every network. Custody calls (`settle`, `deposit_funds`, `withdraw_funds`) read it. + */ +export const ACCUMULATOR_ROOT_ID = '0xacc'; diff --git a/packages/deepbook-predict/sui-codegen.config.ts b/packages/deepbook-predict/sui-codegen.config.ts new file mode 100644 index 000000000..e53555a64 --- /dev/null +++ b/packages/deepbook-predict/sui-codegen.config.ts @@ -0,0 +1,33 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import type { SuiCodegenConfig } from '@mysten/codegen'; + +// Predict is not yet published, so we generate from the local Move source in the +// sibling `deepbookv3` checkout (same pattern deepbook-v3 uses for `@deepbook/core`). +// The generated `src/contracts/**` is used primarily as a BCS-schema source; the +// hand-written `src/transactions/**` layer builds moveCalls against package IDs +// resolved at runtime from `PredictConfig`. +// +// Oracle is read-only for v1: trade entrypoints read feeds by reference, so we do +// not generate `block_scholes_oracle` / `pyth_lazer` (they are only needed to +// *construct* oracle updates, which is out of scope for the v1 SDK). +const config: SuiCodegenConfig = { + output: './src/contracts', + packages: [ + { + package: '@local-pkg/deepbook_predict', + path: '../../../deepbookv3/packages/predict', + }, + { + package: '@local-pkg/account', + path: '../../../deepbookv3/packages/account', + }, + { + package: '@local-pkg/propbook', + path: '../../../deepbookv3/packages/propbook', + }, + ], +}; + +export default config; diff --git a/packages/deepbook-predict/tsconfig.json b/packages/deepbook-predict/tsconfig.json new file mode 100644 index 000000000..676a8abb9 --- /dev/null +++ b/packages/deepbook-predict/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.shared.json", + "include": ["src"], + "compilerOptions": { + "noEmit": true + } +} diff --git a/packages/deepbook-predict/tsdown.config.ts b/packages/deepbook-predict/tsdown.config.ts new file mode 100644 index 000000000..e66954059 --- /dev/null +++ b/packages/deepbook-predict/tsdown.config.ts @@ -0,0 +1,12 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: 'esm', + dts: true, + outDir: 'dist', + unbundle: true, +}); diff --git a/packages/deepbook-predict/vitest.config.mts b/packages/deepbook-predict/vitest.config.mts new file mode 100644 index 000000000..3f63e2781 --- /dev/null +++ b/packages/deepbook-predict/vitest.config.mts @@ -0,0 +1,18 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + maxConcurrency: 8, + hookTimeout: 1000000, + testTimeout: 1000000, + env: { + NODE_ENV: 'test', + }, + }, + resolve: { + alias: {}, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fbbb432d9..aad03181a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,7 +36,7 @@ importers: version: 9.2.1 graphql-config: specifier: ^5.1.5 - version: 5.1.6(@types/node@25.5.0)(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.13.2)(typescript@5.9.3)(utf-8-validate@6.0.6) + version: 5.1.6(@types/node@25.5.0)(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.14.2)(typescript@5.9.3)(utf-8-validate@6.0.6) oxlint: specifier: 1.47.0 version: 1.47.0(oxlint-tsgolint@0.11.5) @@ -85,7 +85,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/codegen: dependencies: @@ -122,7 +122,7 @@ importers: devDependencies: vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/create-dapp: dependencies: @@ -442,7 +442,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/dapp-kit/packages/dapp-kit-react: dependencies: @@ -558,7 +558,7 @@ importers: version: 20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6) jsdom: specifier: ^27.4.0 - version: 27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + version: 27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6) postcss: specifier: '>=8.5.10' version: 8.5.14 @@ -576,7 +576,29 @@ importers: version: 8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + + packages/deepbook-predict: + dependencies: + '@mysten/bcs': + specifier: workspace:^ + version: link:../bcs + '@mysten/sui': + specifier: workspace:^ + version: link:../sui + devDependencies: + '@mysten/codegen': + specifier: workspace:^ + version: link:../codegen + '@types/node': + specifier: ^25.0.8 + version: 25.5.0 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vitest: + specifier: ^4.0.17 + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/deepbook-v3: dependencies: @@ -841,7 +863,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/enoki-connect/demo-dapp: dependencies: @@ -927,7 +949,7 @@ importers: version: 8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) wait-on: specifier: ^9.0.3 version: 9.0.4 @@ -970,7 +992,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/move-bytecode-template: devDependencies: @@ -982,7 +1004,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/mvr-static: dependencies: @@ -1007,7 +1029,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/pas: dependencies: @@ -1032,7 +1054,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/payment-kit: dependencies: @@ -1051,7 +1073,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/seal: dependencies: @@ -1129,7 +1151,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/signers/gcp: dependencies: @@ -1157,7 +1179,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/signers/ledger: dependencies: @@ -1176,7 +1198,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/signers/webcrypto: dependencies: @@ -1195,7 +1217,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/slush-wallet: dependencies: @@ -1223,7 +1245,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/sui: dependencies: @@ -1369,7 +1391,7 @@ importers: version: 8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/utils: dependencies: @@ -1382,7 +1404,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/wallet-sdk: dependencies: @@ -1391,7 +1413,7 @@ importers: version: link:../bcs '@mysten/sui': specifier: '*' - version: link:../sui + version: 2.20.1(typescript@5.9.3) '@mysten/wallet-standard': specifier: workspace:^ version: link:../wallet-standard @@ -1413,13 +1435,13 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/wallet-standard: dependencies: '@mysten/sui': specifier: '*' - version: link:../sui + version: 2.20.1(typescript@5.9.3) '@wallet-standard/core': specifier: 1.1.1 version: 1.1.1 @@ -1457,7 +1479,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/walletconnect-wallet/demo-dapp: dependencies: @@ -1576,7 +1598,7 @@ importers: version: 8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/walrus-wasm: devDependencies: @@ -1588,7 +1610,7 @@ importers: version: 8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/window-wallet-core: dependencies: @@ -1607,7 +1629,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/zksend: dependencies: @@ -1641,7 +1663,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.0.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages: @@ -1653,12 +1675,26 @@ packages: graphql: optional: true + '@0no-co/graphql.web@1.3.2': + resolution: {integrity: sha512-Q1+pRlLhE31GOY/2c9BAEnFTNxO7Awtc6fhhEDlxyCBQ2N0IhD32cPVvPChrK9mwBNSgRdW/sF1kd2e0ojHj1Q==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 + peerDependenciesMeta: + graphql: + optional: true + '@0no-co/graphqlsp@1.15.2': resolution: {integrity: sha512-Ys031WnS3sTQQBtRTkQsYnw372OlW72ais4sp0oh2UMPRNyxxnq85zRfU4PIdoy9kWriysPT5BYAkgIxhbonFA==} peerDependencies: graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 typescript: ^5.0.0 + '@0no-co/graphqlsp@1.17.3': + resolution: {integrity: sha512-4PPvxDPmbntddpgMyA3VId5/E9YGdRuuS/mW+THOvtTx/C79Pf+lN28LkNNACJrF9L7YACiAJelyOkC6LqUzvw==} + peerDependencies: + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 + typescript: ^5.0.0 || ^6.0.0 + '@acemir/cssom@0.9.31': resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} @@ -2223,12 +2259,32 @@ packages: '@gql.tada/vue-support': optional: true + '@gql.tada/cli-utils@1.9.2': + resolution: {integrity: sha512-cVNs4v8ewLRYJfyAsaHbiAmd5Hm+zXEMvMhBksH58ZU87d6f8crsp2CQG6QtIqnJJw1q0CBWfWTZepGWNcL3QA==} + peerDependencies: + '@0no-co/graphqlsp': ^1.16.0 + '@gql.tada/svelte-support': 1.0.3 + '@gql.tada/vue-support': 1.0.3 + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@gql.tada/svelte-support': + optional: true + '@gql.tada/vue-support': + optional: true + '@gql.tada/internal@1.0.8': resolution: {integrity: sha512-XYdxJhtHC5WtZfdDqtKjcQ4d7R1s0d1rnlSs3OcBEUbYiPoJJfZU7tWsVXuv047Z6msvmr4ompJ7eLSK5Km57g==} peerDependencies: graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 typescript: ^5.0.0 + '@gql.tada/internal@1.2.1': + resolution: {integrity: sha512-1kPMv9KRpD6mfVwtXK+iy43U/gi4bpr4ganfhPLD0TjxpbuVJm7CtZ9wMFdwy3FjLBFN2QhwscNnL7lRPHg4vg==} + peerDependencies: + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + '@graphql-codegen/add@6.0.0': resolution: {integrity: sha512-biFdaURX0KTwEJPQ1wkT6BRgNasqgQ5KbCI1a3zwtLtO7XTo7/vKITPylmiU27K5DSOWYnY/1jfSqUAEBuhZrQ==} engines: {node: '>=16'} @@ -2969,6 +3025,16 @@ packages: resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} engines: {node: '>=18'} + '@mysten/bcs@2.1.0': + resolution: {integrity: sha512-rIR/cDAqDfBDxmYEZXppN/on8gmh1OW0dYi/Bk2kMBZcYMTaBaEtEX1VR6g7HicVxuMbFAIP0/SQkdH7J9Y5dQ==} + + '@mysten/sui@2.20.1': + resolution: {integrity: sha512-gf7p3biAr+456dIFHFZUEvUn52vFhkjdJ6zM8FQoC9Ox75ApfkM8vT6iUiSNBjkNlGWJ54g3+6hHYv75F+ST4A==} + engines: {node: '>=22'} + + '@mysten/utils@0.4.0': + resolution: {integrity: sha512-nHlXECBl9kE+AHF/aw5a7JVNizae8Kb71A4H18BV/sXd5/l2BaWNGWVatq05fzJo3hF78AWorDxa++1TgcBKWw==} + '@nanostores/lit@0.2.3': resolution: {integrity: sha512-hIUKzdNrgKXkXCsppzQxmYYYMTn96cncijWhzcYZKn3Yimqj7B6YK94qN/KObjBNEe0xR3JLgMo96ew5fVtW2w==} peerDependencies: @@ -3074,6 +3140,10 @@ packages: resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} engines: {node: '>= 20.19.0'} + '@noble/curves@2.2.0': + resolution: {integrity: sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==} + engines: {node: '>= 20.19.0'} + '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} @@ -3090,6 +3160,10 @@ packages: resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} engines: {node: '>= 20.19.0'} + '@noble/hashes@2.2.0': + resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} + engines: {node: '>= 20.19.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -4584,18 +4658,27 @@ packages: '@scure/base@2.0.0': resolution: {integrity: sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==} + '@scure/base@2.2.0': + resolution: {integrity: sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==} + '@scure/bip32@1.7.0': resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} '@scure/bip32@2.0.1': resolution: {integrity: sha512-4Md1NI5BzoVP+bhyJaY3K6yMesEFzNS1sE/cP+9nuvE7p/b0kx9XbpDHHFl8dHtufcbdHRUUQdRqLIPHN/s7yA==} + '@scure/bip32@2.2.0': + resolution: {integrity: sha512-zFr7t2F+a9+5tB7QbarF2HQNYrgjCNaoLAupZdKkrFMYMozJf5zqH2WJCQibMzm1qQ0QogrxVGO3qXfQDYMaQg==} + '@scure/bip39@1.6.0': resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} '@scure/bip39@2.0.1': resolution: {integrity: sha512-PsxdFj/d2AcJcZDX1FXN3dDgitDDTmwf78rKZq1a6c1P1Nan1X/Sxc7667zU3U+AN60g7SxxP0YCVw2H/hBycg==} + '@scure/bip39@2.2.0': + resolution: {integrity: sha512-T/Bj/YvYMNkIPq6EENO6/rcs2e7qTNuyoUXf0KBFDmp0ZDu0H2X4Lq6yC3i0c8PcWkov5EbW+yQZZbdMmk154A==} + '@shikijs/core@3.23.0': resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} @@ -7109,6 +7192,12 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + gql.tada@1.11.2: + resolution: {integrity: sha512-oBr7ShA5/TmcwOO7BZgN1SynX2rBU+/ltysB0zXc+NCBF+9YOg6MRzJcTfLjIqDKdcE3LGxpOl0l9hBbxmyzmA==} + hasBin: true + peerDependencies: + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + gql.tada@1.9.1: resolution: {integrity: sha512-Ijtwgw08aE7l06wK5oj5Msgpk9SUe5FSVcuxU5dHyefdM7fDqLQpA76yHBoq8lPB3MNSir8tznodDknHkm2Z/w==} hasBin: true @@ -7157,6 +7246,10 @@ packages: resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + graphql@16.14.2: + resolution: {integrity: sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + h3@1.15.10: resolution: {integrity: sha512-YzJeWSkDZxAhvmp8dexjRK5hxziRO7I9m0N53WhvYL5NiWfkUkzssVzY9jvGu0HBoLFW6+duYmNSn6MaZBCCtg==} @@ -9531,6 +9624,14 @@ packages: typescript: optional: true + valibot@1.4.2: + resolution: {integrity: sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + validate-npm-package-name@5.0.1: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -9921,12 +10022,22 @@ snapshots: optionalDependencies: graphql: 16.13.2 + '@0no-co/graphql.web@1.3.2(graphql@16.14.2)': + optionalDependencies: + graphql: 16.14.2 + '@0no-co/graphqlsp@1.15.2(graphql@16.13.2)(typescript@5.9.3)': dependencies: '@gql.tada/internal': 1.0.8(graphql@16.13.2)(typescript@5.9.3) graphql: 16.13.2 typescript: 5.9.3 + '@0no-co/graphqlsp@1.17.3(graphql@16.14.2)(typescript@5.9.3)': + dependencies: + '@gql.tada/internal': 1.2.1(graphql@16.14.2)(typescript@5.9.3) + graphql: 16.14.2 + typescript: 5.9.3 + '@acemir/cssom@0.9.31': {} '@adobe/css-tools@4.4.4': {} @@ -10533,6 +10644,11 @@ snapshots: '@exodus/bytes@1.15.0(@noble/hashes@2.0.1)': optionalDependencies: '@noble/hashes': 2.0.1 + optional: true + + '@exodus/bytes@1.15.0(@noble/hashes@2.2.0)': + optionalDependencies: + '@noble/hashes': 2.2.0 '@fastify/busboy@3.2.0': {} @@ -10596,12 +10712,25 @@ snapshots: graphql: 16.13.2 typescript: 5.9.3 + '@gql.tada/cli-utils@1.9.2(@0no-co/graphqlsp@1.17.3(graphql@16.14.2)(typescript@5.9.3))(graphql@16.14.2)(typescript@5.9.3)': + dependencies: + '@0no-co/graphqlsp': 1.17.3(graphql@16.14.2)(typescript@5.9.3) + '@gql.tada/internal': 1.2.1(graphql@16.14.2)(typescript@5.9.3) + graphql: 16.14.2 + typescript: 5.9.3 + '@gql.tada/internal@1.0.8(graphql@16.13.2)(typescript@5.9.3)': dependencies: '@0no-co/graphql.web': 1.2.0(graphql@16.13.2) graphql: 16.13.2 typescript: 5.9.3 + '@gql.tada/internal@1.2.1(graphql@16.14.2)(typescript@5.9.3)': + dependencies: + '@0no-co/graphql.web': 1.3.2(graphql@16.14.2) + graphql: 16.14.2 + typescript: 5.9.3 + '@graphql-codegen/add@6.0.0(graphql@16.13.2)': dependencies: '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.2) @@ -10800,6 +10929,14 @@ snapshots: graphql: 16.13.2 tslib: 2.8.1 + '@graphql-tools/batch-execute@10.0.7(graphql@16.14.2)': + dependencies: + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@whatwg-node/promise-helpers': 1.3.2 + dataloader: 2.2.3 + graphql: 16.14.2 + tslib: 2.8.1 + '@graphql-tools/code-file-loader@8.1.28(graphql@16.13.2)': dependencies: '@graphql-tools/graphql-tag-pluck': 8.3.27(graphql@16.13.2) @@ -10823,6 +10960,18 @@ snapshots: graphql: 16.13.2 tslib: 2.8.1 + '@graphql-tools/delegate@12.0.12(graphql@16.14.2)': + dependencies: + '@graphql-tools/batch-execute': 10.0.7(graphql@16.14.2) + '@graphql-tools/executor': 1.5.1(graphql@16.14.2) + '@graphql-tools/schema': 10.0.31(graphql@16.14.2) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@repeaterjs/repeater': 3.0.6 + '@whatwg-node/promise-helpers': 1.3.2 + dataloader: 2.2.3 + graphql: 16.14.2 + tslib: 2.8.1 + '@graphql-tools/documents@1.0.1(graphql@16.13.2)': dependencies: graphql: 16.13.2 @@ -10835,6 +10984,12 @@ snapshots: '@graphql-tools/utils': 11.0.0(graphql@16.13.2) graphql: 16.13.2 + '@graphql-tools/executor-common@1.0.6(graphql@16.14.2)': + dependencies: + '@envelop/core': 5.5.1 + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + graphql: 16.14.2 + '@graphql-tools/executor-graphql-ws@3.1.5(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.13.2)(utf-8-validate@6.0.6)': dependencies: '@graphql-tools/executor-common': 1.0.6(graphql@16.13.2) @@ -10851,6 +11006,22 @@ snapshots: - crossws - utf-8-validate + '@graphql-tools/executor-graphql-ws@3.1.5(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.14.2)(utf-8-validate@6.0.6)': + dependencies: + '@graphql-tools/executor-common': 1.0.6(graphql@16.14.2) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@whatwg-node/disposablestack': 0.0.6 + graphql: 16.14.2 + graphql-ws: 6.0.7(crossws@0.3.5)(graphql@16.14.2)(ws@8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + isows: 1.0.7(ws@8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + tslib: 2.8.1 + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - '@fastify/websocket' + - bufferutil + - crossws + - utf-8-validate + '@graphql-tools/executor-http@3.1.1(@types/node@25.5.0)(graphql@16.13.2)': dependencies: '@graphql-hive/signal': 2.0.0 @@ -10866,6 +11037,21 @@ snapshots: transitivePeerDependencies: - '@types/node' + '@graphql-tools/executor-http@3.1.1(@types/node@25.5.0)(graphql@16.14.2)': + dependencies: + '@graphql-hive/signal': 2.0.0 + '@graphql-tools/executor-common': 1.0.6(graphql@16.14.2) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@repeaterjs/repeater': 3.0.6 + '@whatwg-node/disposablestack': 0.0.6 + '@whatwg-node/fetch': 0.10.13 + '@whatwg-node/promise-helpers': 1.3.2 + graphql: 16.14.2 + meros: 1.3.2(@types/node@25.5.0) + tslib: 2.8.1 + transitivePeerDependencies: + - '@types/node' + '@graphql-tools/executor-legacy-ws@1.1.25(bufferutil@4.1.0)(graphql@16.13.2)(utf-8-validate@6.0.6)': dependencies: '@graphql-tools/utils': 11.0.0(graphql@16.13.2) @@ -10878,6 +11064,18 @@ snapshots: - bufferutil - utf-8-validate + '@graphql-tools/executor-legacy-ws@1.1.25(bufferutil@4.1.0)(graphql@16.14.2)(utf-8-validate@6.0.6)': + dependencies: + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@types/ws': 8.18.1 + graphql: 16.14.2 + isomorphic-ws: 5.0.0(ws@8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + tslib: 2.8.1 + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@graphql-tools/executor@1.5.1(graphql@16.13.2)': dependencies: '@graphql-tools/utils': 11.0.0(graphql@16.13.2) @@ -10888,6 +11086,16 @@ snapshots: graphql: 16.13.2 tslib: 2.8.1 + '@graphql-tools/executor@1.5.1(graphql@16.14.2)': + dependencies: + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.14.2) + '@repeaterjs/repeater': 3.0.6 + '@whatwg-node/disposablestack': 0.0.6 + '@whatwg-node/promise-helpers': 1.3.2 + graphql: 16.14.2 + tslib: 2.8.1 + '@graphql-tools/git-loader@8.0.32(graphql@16.13.2)': dependencies: '@graphql-tools/graphql-tag-pluck': 8.3.27(graphql@16.13.2) @@ -10923,6 +11131,15 @@ snapshots: tslib: 2.8.1 unixify: 1.0.0 + '@graphql-tools/graphql-file-loader@8.1.12(graphql@16.14.2)': + dependencies: + '@graphql-tools/import': 7.1.12(graphql@16.14.2) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + globby: 11.1.0 + graphql: 16.14.2 + tslib: 2.8.1 + unixify: 1.0.0 + '@graphql-tools/graphql-tag-pluck@8.3.27(graphql@16.13.2)': dependencies: '@babel/core': 7.29.0 @@ -10943,6 +11160,13 @@ snapshots: resolve-from: 5.0.0 tslib: 2.8.1 + '@graphql-tools/import@7.1.12(graphql@16.14.2)': + dependencies: + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + graphql: 16.14.2 + resolve-from: 5.0.0 + tslib: 2.8.1 + '@graphql-tools/json-file-loader@8.0.26(graphql@16.13.2)': dependencies: '@graphql-tools/utils': 11.0.0(graphql@16.13.2) @@ -10951,6 +11175,14 @@ snapshots: tslib: 2.8.1 unixify: 1.0.0 + '@graphql-tools/json-file-loader@8.0.26(graphql@16.14.2)': + dependencies: + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + globby: 11.1.0 + graphql: 16.14.2 + tslib: 2.8.1 + unixify: 1.0.0 + '@graphql-tools/load@8.1.8(graphql@16.13.2)': dependencies: '@graphql-tools/schema': 10.0.31(graphql@16.13.2) @@ -10959,12 +11191,26 @@ snapshots: p-limit: 3.1.0 tslib: 2.8.1 + '@graphql-tools/load@8.1.8(graphql@16.14.2)': + dependencies: + '@graphql-tools/schema': 10.0.31(graphql@16.14.2) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + graphql: 16.14.2 + p-limit: 3.1.0 + tslib: 2.8.1 + '@graphql-tools/merge@9.1.7(graphql@16.13.2)': dependencies: '@graphql-tools/utils': 11.0.0(graphql@16.13.2) graphql: 16.13.2 tslib: 2.8.1 + '@graphql-tools/merge@9.1.7(graphql@16.14.2)': + dependencies: + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + graphql: 16.14.2 + tslib: 2.8.1 + '@graphql-tools/optimize@2.0.0(graphql@16.13.2)': dependencies: graphql: 16.13.2 @@ -10984,6 +11230,13 @@ snapshots: graphql: 16.13.2 tslib: 2.8.1 + '@graphql-tools/schema@10.0.31(graphql@16.14.2)': + dependencies: + '@graphql-tools/merge': 9.1.7(graphql@16.14.2) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + graphql: 16.14.2 + tslib: 2.8.1 + '@graphql-tools/url-loader@9.0.6(@types/node@25.5.0)(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.13.2)(utf-8-validate@6.0.6)': dependencies: '@graphql-tools/executor-graphql-ws': 3.1.5(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.13.2)(utf-8-validate@6.0.6) @@ -11006,6 +11259,28 @@ snapshots: - crossws - utf-8-validate + '@graphql-tools/url-loader@9.0.6(@types/node@25.5.0)(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.14.2)(utf-8-validate@6.0.6)': + dependencies: + '@graphql-tools/executor-graphql-ws': 3.1.5(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.14.2)(utf-8-validate@6.0.6) + '@graphql-tools/executor-http': 3.1.1(@types/node@25.5.0)(graphql@16.14.2) + '@graphql-tools/executor-legacy-ws': 1.1.25(bufferutil@4.1.0)(graphql@16.14.2)(utf-8-validate@6.0.6) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@graphql-tools/wrap': 11.1.12(graphql@16.14.2) + '@types/ws': 8.18.1 + '@whatwg-node/fetch': 0.10.13 + '@whatwg-node/promise-helpers': 1.3.2 + graphql: 16.14.2 + isomorphic-ws: 5.0.0(ws@8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + sync-fetch: 0.6.0 + tslib: 2.8.1 + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - '@fastify/websocket' + - '@types/node' + - bufferutil + - crossws + - utf-8-validate + '@graphql-tools/utils@10.11.0(graphql@16.13.2)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) @@ -11022,6 +11297,14 @@ snapshots: graphql: 16.13.2 tslib: 2.8.1 + '@graphql-tools/utils@11.0.0(graphql@16.14.2)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.14.2) + '@whatwg-node/promise-helpers': 1.3.2 + cross-inspect: 1.0.1 + graphql: 16.14.2 + tslib: 2.8.1 + '@graphql-tools/wrap@11.1.12(graphql@16.13.2)': dependencies: '@graphql-tools/delegate': 12.0.12(graphql@16.13.2) @@ -11031,10 +11314,23 @@ snapshots: graphql: 16.13.2 tslib: 2.8.1 + '@graphql-tools/wrap@11.1.12(graphql@16.14.2)': + dependencies: + '@graphql-tools/delegate': 12.0.12(graphql@16.14.2) + '@graphql-tools/schema': 10.0.31(graphql@16.14.2) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + '@whatwg-node/promise-helpers': 1.3.2 + graphql: 16.14.2 + tslib: 2.8.1 + '@graphql-typed-document-node/core@3.2.0(graphql@16.13.2)': dependencies: graphql: 16.13.2 + '@graphql-typed-document-node/core@3.2.0(graphql@16.14.2)': + dependencies: + graphql: 16.14.2 + '@grpc/grpc-js@1.14.3': dependencies: '@grpc/proto-loader': 0.8.0 @@ -11551,6 +11847,37 @@ snapshots: outvariant: 1.4.3 strict-event-emitter: 0.5.1 + '@mysten/bcs@2.1.0': + dependencies: + '@mysten/utils': 0.4.0 + '@scure/base': 2.2.0 + + '@mysten/sui@2.20.1(typescript@5.9.3)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.14.2) + '@mysten/bcs': 2.1.0 + '@mysten/utils': 0.4.0 + '@noble/curves': 2.2.0 + '@noble/hashes': 2.2.0 + '@protobuf-ts/grpcweb-transport': 2.11.1 + '@protobuf-ts/runtime': 2.11.1 + '@protobuf-ts/runtime-rpc': 2.11.1 + '@scure/base': 2.2.0 + '@scure/bip32': 2.2.0 + '@scure/bip39': 2.2.0 + gql.tada: 1.11.2(graphql@16.14.2)(typescript@5.9.3) + graphql: 16.14.2 + poseidon-lite: 0.2.1 + valibot: 1.4.2(typescript@5.9.3) + transitivePeerDependencies: + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - typescript + + '@mysten/utils@0.4.0': + dependencies: + '@scure/base': 2.2.0 + '@nanostores/lit@0.2.3(lit@3.3.2)(nanostores@1.2.0)': dependencies: lit: 3.3.2 @@ -11617,6 +11944,10 @@ snapshots: dependencies: '@noble/hashes': 2.0.1 + '@noble/curves@2.2.0': + dependencies: + '@noble/hashes': 2.2.0 + '@noble/hashes@1.4.0': optional: true @@ -11626,6 +11957,8 @@ snapshots: '@noble/hashes@2.0.1': {} + '@noble/hashes@2.2.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -13165,6 +13498,8 @@ snapshots: '@scure/base@2.0.0': {} + '@scure/base@2.2.0': {} + '@scure/bip32@1.7.0': dependencies: '@noble/curves': 1.9.7 @@ -13177,6 +13512,12 @@ snapshots: '@noble/hashes': 2.0.1 '@scure/base': 2.0.0 + '@scure/bip32@2.2.0': + dependencies: + '@noble/curves': 2.2.0 + '@noble/hashes': 2.2.0 + '@scure/base': 2.2.0 + '@scure/bip39@1.6.0': dependencies: '@noble/hashes': 1.8.0 @@ -13187,6 +13528,11 @@ snapshots: '@noble/hashes': 2.0.1 '@scure/base': 2.0.0 + '@scure/bip39@2.2.0': + dependencies: + '@noble/hashes': 2.2.0 + '@scure/base': 2.2.0 + '@shikijs/core@3.23.0': dependencies: '@shikijs/types': 3.23.0 @@ -16202,6 +16548,18 @@ snapshots: gopd@1.2.0: {} + gql.tada@1.11.2(graphql@16.14.2)(typescript@5.9.3): + dependencies: + '@0no-co/graphql.web': 1.3.2(graphql@16.14.2) + '@0no-co/graphqlsp': 1.17.3(graphql@16.14.2)(typescript@5.9.3) + '@gql.tada/cli-utils': 1.9.2(@0no-co/graphqlsp@1.17.3(graphql@16.14.2)(typescript@5.9.3))(graphql@16.14.2)(typescript@5.9.3) + '@gql.tada/internal': 1.2.1(graphql@16.14.2)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - graphql + gql.tada@1.9.1(graphql@16.13.2)(typescript@5.9.3): dependencies: '@0no-co/graphql.web': 1.2.0(graphql@16.13.2) @@ -16240,6 +16598,28 @@ snapshots: - typescript - utf-8-validate + graphql-config@5.1.6(@types/node@25.5.0)(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.14.2)(typescript@5.9.3)(utf-8-validate@6.0.6): + dependencies: + '@graphql-tools/graphql-file-loader': 8.1.12(graphql@16.14.2) + '@graphql-tools/json-file-loader': 8.0.26(graphql@16.14.2) + '@graphql-tools/load': 8.1.8(graphql@16.14.2) + '@graphql-tools/merge': 9.1.7(graphql@16.14.2) + '@graphql-tools/url-loader': 9.0.6(@types/node@25.5.0)(bufferutil@4.1.0)(crossws@0.3.5)(graphql@16.14.2)(utf-8-validate@6.0.6) + '@graphql-tools/utils': 11.0.0(graphql@16.14.2) + cosmiconfig: 8.3.6(typescript@5.9.3) + graphql: 16.14.2 + jiti: 2.6.1 + minimatch: 10.2.4 + string-env-interpolation: 1.0.1 + tslib: 2.8.1 + transitivePeerDependencies: + - '@fastify/websocket' + - '@types/node' + - bufferutil + - crossws + - typescript + - utf-8-validate + graphql-tag@2.12.6(graphql@16.13.2): dependencies: graphql: 16.13.2 @@ -16252,8 +16632,17 @@ snapshots: crossws: 0.3.5 ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + graphql-ws@6.0.7(crossws@0.3.5)(graphql@16.14.2)(ws@8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)): + dependencies: + graphql: 16.14.2 + optionalDependencies: + crossws: 0.3.5 + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + graphql@16.13.2: {} + graphql@16.14.2: {} + h3@1.15.10: dependencies: cookie-es: 1.2.2 @@ -16371,6 +16760,13 @@ snapshots: '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) transitivePeerDependencies: - '@noble/hashes' + optional: true + + html-encoding-sniffer@6.0.0(@noble/hashes@2.2.0): + dependencies: + '@exodus/bytes': 1.15.0(@noble/hashes@2.2.0) + transitivePeerDependencies: + - '@noble/hashes' html-escaper@3.0.3: {} @@ -16620,6 +17016,35 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true + + jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6): + dependencies: + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.8.1 + '@exodus/bytes': 1.15.0(@noble/hashes@2.2.0) + cssstyle: 5.3.7 + data-urls: 6.0.1 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0(@noble/hashes@2.2.0) + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + parse5: 8.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + - bufferutil + - supports-color + - utf-8-validate jsesc@3.1.0: {} @@ -19130,6 +19555,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + valibot@1.4.2(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + validate-npm-package-name@5.0.1: {} validate-npm-package-name@6.0.2: {} @@ -19260,6 +19689,35 @@ snapshots: transitivePeerDependencies: - msw + vitest@4.1.1(@types/node@25.5.0)(happy-dom@20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.1 + '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.1 + '@vitest/runner': 4.1.1 + '@vitest/snapshot': 4.1.1 + '@vitest/spy': 4.1.1 + '@vitest/utils': 4.1.1 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.5(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.5.0 + happy-dom: 20.8.9(bufferutil@4.1.0)(utf-8-validate@6.0.6) + jsdom: 27.4.0(@noble/hashes@2.2.0)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - msw + vm2@3.11.2: dependencies: acorn: 8.16.0