@mysten/deepbook-v3 2.6.4 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/PREDICT.md +389 -61
  3. package/dist/contracts/account/account.d.mts +23 -23
  4. package/dist/contracts/account/account.d.mts.map +1 -1
  5. package/dist/contracts/account/account_registry.d.mts +13 -13
  6. package/dist/contracts/deepbook/account.d.mts +18 -18
  7. package/dist/contracts/deepbook/balances.d.mts +4 -4
  8. package/dist/contracts/deepbook/deep_price.d.mts +3 -3
  9. package/dist/contracts/deepbook/order.d.mts +12 -12
  10. package/dist/contracts/deepbook_predict/admin.d.mts +4 -4
  11. package/dist/contracts/deepbook_predict/builder_code.d.mts +11 -11
  12. package/dist/contracts/deepbook_predict/builder_code_events.d.mts +10 -10
  13. package/dist/contracts/deepbook_predict/config_events.d.mts +93 -68
  14. package/dist/contracts/deepbook_predict/config_events.d.mts.map +1 -1
  15. package/dist/contracts/deepbook_predict/config_events.mjs +45 -1
  16. package/dist/contracts/deepbook_predict/config_events.mjs.map +1 -1
  17. package/dist/contracts/deepbook_predict/deps/std/type_name.mjs +17 -0
  18. package/dist/contracts/deepbook_predict/deps/std/type_name.mjs.map +1 -0
  19. package/dist/contracts/deepbook_predict/expiry_market.d.mts +652 -235
  20. package/dist/contracts/deepbook_predict/expiry_market.d.mts.map +1 -1
  21. package/dist/contracts/deepbook_predict/expiry_market.mjs +652 -186
  22. package/dist/contracts/deepbook_predict/expiry_market.mjs.map +1 -1
  23. package/dist/contracts/deepbook_predict/lp_book.mjs +1 -1
  24. package/dist/contracts/deepbook_predict/market_lifecycle_cap.d.mts +5 -5
  25. package/dist/contracts/deepbook_predict/market_manager.d.mts +27 -27
  26. package/dist/contracts/deepbook_predict/order_events.d.mts +50 -50
  27. package/dist/contracts/deepbook_predict/order_events.d.mts.map +1 -1
  28. package/dist/contracts/deepbook_predict/order_events.mjs +3 -1
  29. package/dist/contracts/deepbook_predict/order_events.mjs.map +1 -1
  30. package/dist/contracts/deepbook_predict/pause_cap.d.mts +5 -5
  31. package/dist/contracts/deepbook_predict/plp.d.mts +184 -82
  32. package/dist/contracts/deepbook_predict/plp.d.mts.map +1 -1
  33. package/dist/contracts/deepbook_predict/plp.mjs +126 -7
  34. package/dist/contracts/deepbook_predict/plp.mjs.map +1 -1
  35. package/dist/contracts/deepbook_predict/pool_accounting.mjs +1 -1
  36. package/dist/contracts/deepbook_predict/pool_valuation_cap.d.mts +5 -5
  37. package/dist/contracts/deepbook_predict/predict_account.d.mts +14 -14
  38. package/dist/contracts/deepbook_predict/pricing.d.mts +91 -58
  39. package/dist/contracts/deepbook_predict/pricing.d.mts.map +1 -1
  40. package/dist/contracts/deepbook_predict/pricing.mjs +30 -3
  41. package/dist/contracts/deepbook_predict/pricing.mjs.map +1 -1
  42. package/dist/contracts/deepbook_predict/pricing_config.mjs.map +1 -1
  43. package/dist/contracts/deepbook_predict/protocol_config.d.mts +400 -92
  44. package/dist/contracts/deepbook_predict/protocol_config.d.mts.map +1 -1
  45. package/dist/contracts/deepbook_predict/protocol_config.mjs +451 -61
  46. package/dist/contracts/deepbook_predict/protocol_config.mjs.map +1 -1
  47. package/dist/contracts/deepbook_predict/range_codec.d.mts +2 -2
  48. package/dist/contracts/deepbook_predict/registry.d.mts +28 -28
  49. package/dist/contracts/deepbook_predict/strike_exposure.mjs +1 -1
  50. package/dist/contracts/deepbook_predict/strike_payout_tree.mjs +17 -12
  51. package/dist/contracts/deepbook_predict/strike_payout_tree.mjs.map +1 -1
  52. package/dist/contracts/deepbook_predict/vault_events.d.mts +154 -106
  53. package/dist/contracts/deepbook_predict/vault_events.d.mts.map +1 -1
  54. package/dist/contracts/deepbook_predict/vault_events.mjs +57 -1
  55. package/dist/contracts/deepbook_predict/vault_events.mjs.map +1 -1
  56. package/dist/contracts/deepbook_predict_math/config-arguments.d.mts +10 -0
  57. package/dist/contracts/deepbook_predict_math/config-arguments.d.mts.map +1 -0
  58. package/dist/contracts/deepbook_predict_math/lazer_price.d.mts +106 -0
  59. package/dist/contracts/deepbook_predict_math/lazer_price.d.mts.map +1 -0
  60. package/dist/contracts/deepbook_predict_math/lazer_price.mjs +125 -0
  61. package/dist/contracts/deepbook_predict_math/lazer_price.mjs.map +1 -0
  62. package/dist/contracts/deepbook_predict_math/math.d.mts +284 -0
  63. package/dist/contracts/deepbook_predict_math/math.d.mts.map +1 -0
  64. package/dist/contracts/deepbook_predict_math/math.mjs +364 -0
  65. package/dist/contracts/deepbook_predict_math/math.mjs.map +1 -0
  66. package/dist/contracts/deepbook_predict_orders/config-arguments.d.mts +13 -0
  67. package/dist/contracts/deepbook_predict_orders/config-arguments.d.mts.map +1 -0
  68. package/dist/contracts/deepbook_predict_orders/delayed_execution_config.d.mts +215 -0
  69. package/dist/contracts/deepbook_predict_orders/delayed_execution_config.d.mts.map +1 -0
  70. package/dist/contracts/deepbook_predict_orders/delayed_execution_config.mjs +215 -0
  71. package/dist/contracts/deepbook_predict_orders/delayed_execution_config.mjs.map +1 -0
  72. package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/expiry_market.mjs +87 -0
  73. package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/expiry_market.mjs.map +1 -0
  74. package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/pricing.mjs +52 -0
  75. package/dist/contracts/deepbook_predict_orders/deps/deepbook_predict/pricing.mjs.map +1 -0
  76. package/dist/contracts/deepbook_predict_orders/deps/fixed_math/i64.mjs +25 -0
  77. package/dist/contracts/deepbook_predict_orders/deps/fixed_math/i64.mjs.map +1 -0
  78. package/dist/contracts/deepbook_predict_orders/deps/sui/balance.mjs +21 -0
  79. package/dist/contracts/deepbook_predict_orders/deps/sui/balance.mjs.map +1 -0
  80. package/dist/contracts/deepbook_predict_orders/deps/sui/table.mjs +39 -0
  81. package/dist/contracts/deepbook_predict_orders/deps/sui/table.mjs.map +1 -0
  82. package/dist/contracts/deepbook_predict_orders/desk.d.mts +187 -0
  83. package/dist/contracts/deepbook_predict_orders/desk.d.mts.map +1 -0
  84. package/dist/contracts/deepbook_predict_orders/desk.mjs +261 -0
  85. package/dist/contracts/deepbook_predict_orders/desk.mjs.map +1 -0
  86. package/dist/contracts/deepbook_predict_orders/order_queue.d.mts +1042 -0
  87. package/dist/contracts/deepbook_predict_orders/order_queue.d.mts.map +1 -0
  88. package/dist/contracts/deepbook_predict_orders/order_queue.mjs +849 -0
  89. package/dist/contracts/deepbook_predict_orders/order_queue.mjs.map +1 -0
  90. package/dist/contracts/deepbook_predict_orders/queue.d.mts +683 -0
  91. package/dist/contracts/deepbook_predict_orders/queue.d.mts.map +1 -0
  92. package/dist/contracts/deepbook_predict_orders/queue.mjs +912 -0
  93. package/dist/contracts/deepbook_predict_orders/queue.mjs.map +1 -0
  94. package/dist/contracts/deepbook_predict_orders/queue_events.d.mts +195 -0
  95. package/dist/contracts/deepbook_predict_orders/queue_events.d.mts.map +1 -0
  96. package/dist/contracts/deepbook_predict_orders/queue_events.mjs +187 -0
  97. package/dist/contracts/deepbook_predict_orders/queue_events.mjs.map +1 -0
  98. package/dist/contracts/deepbook_sessions/session_config.d.mts +8 -8
  99. package/dist/contracts/deepbook_sessions/sessions.d.mts +163 -28
  100. package/dist/contracts/deepbook_sessions/sessions.d.mts.map +1 -1
  101. package/dist/contracts/deepbook_sessions/sessions.mjs +234 -5
  102. package/dist/contracts/deepbook_sessions/sessions.mjs.map +1 -1
  103. package/dist/deployments/mainnet.mjs +7 -4
  104. package/dist/deployments/mainnet.mjs.map +1 -1
  105. package/dist/deployments/testnet.mjs +7 -4
  106. package/dist/deployments/testnet.mjs.map +1 -1
  107. package/dist/predict/bindings/expiry-market.d.mts +77 -0
  108. package/dist/predict/bindings/expiry-market.d.mts.map +1 -0
  109. package/dist/predict/bindings/expiry-market.mjs +139 -0
  110. package/dist/predict/bindings/expiry-market.mjs.map +1 -0
  111. package/dist/predict/bindings/protocol-config.d.mts +39 -0
  112. package/dist/predict/bindings/protocol-config.d.mts.map +1 -0
  113. package/dist/predict/bindings/protocol-config.mjs +90 -0
  114. package/dist/predict/bindings/protocol-config.mjs.map +1 -0
  115. package/dist/predict/bindings/rename.mjs +9 -0
  116. package/dist/predict/bindings/rename.mjs.map +1 -0
  117. package/dist/predict/client.d.mts +595 -16
  118. package/dist/predict/client.d.mts.map +1 -1
  119. package/dist/predict/client.mjs +986 -10
  120. package/dist/predict/client.mjs.map +1 -1
  121. package/dist/predict/config/generated.d.mts +22 -1
  122. package/dist/predict/config/generated.d.mts.map +1 -1
  123. package/dist/predict/config/generated.mjs +30 -1
  124. package/dist/predict/config/generated.mjs.map +1 -1
  125. package/dist/predict/config/mainnet.mjs +11 -3
  126. package/dist/predict/config/mainnet.mjs.map +1 -1
  127. package/dist/predict/config/testnet.mjs +11 -3
  128. package/dist/predict/config/testnet.mjs.map +1 -1
  129. package/dist/predict/config/types.d.mts +50 -1
  130. package/dist/predict/config/types.d.mts.map +1 -1
  131. package/dist/predict/cost.d.mts +38 -11
  132. package/dist/predict/cost.d.mts.map +1 -1
  133. package/dist/predict/cost.mjs +37 -11
  134. package/dist/predict/cost.mjs.map +1 -1
  135. package/dist/predict/decode.d.mts +251 -1
  136. package/dist/predict/decode.d.mts.map +1 -1
  137. package/dist/predict/decode.mjs +342 -4
  138. package/dist/predict/decode.mjs.map +1 -1
  139. package/dist/predict/errors.d.mts +69 -6
  140. package/dist/predict/errors.d.mts.map +1 -1
  141. package/dist/predict/errors.mjs +277 -4
  142. package/dist/predict/errors.mjs.map +1 -1
  143. package/dist/predict/index.d.mts +21 -10
  144. package/dist/predict/index.mjs +24 -12
  145. package/dist/predict/queue-id.d.mts +13 -0
  146. package/dist/predict/queue-id.d.mts.map +1 -0
  147. package/dist/predict/queue-id.mjs +19 -0
  148. package/dist/predict/queue-id.mjs.map +1 -0
  149. package/dist/predict/queue.d.mts +505 -0
  150. package/dist/predict/queue.d.mts.map +1 -0
  151. package/dist/predict/queue.mjs +774 -0
  152. package/dist/predict/queue.mjs.map +1 -0
  153. package/dist/predict/reads/balances.mjs +1 -1
  154. package/dist/predict/reads/markets.mjs +46 -5
  155. package/dist/predict/reads/markets.mjs.map +1 -1
  156. package/dist/predict/reads/pool.mjs +1 -1
  157. package/dist/predict/reads/pricing.d.mts +1 -1
  158. package/dist/predict/reads/queue.d.mts +105 -0
  159. package/dist/predict/reads/queue.d.mts.map +1 -0
  160. package/dist/predict/reads/queue.mjs +445 -0
  161. package/dist/predict/reads/queue.mjs.map +1 -0
  162. package/dist/predict/ticks.d.mts +9 -1
  163. package/dist/predict/ticks.d.mts.map +1 -1
  164. package/dist/predict/ticks.mjs +18 -1
  165. package/dist/predict/ticks.mjs.map +1 -1
  166. package/dist/predict/tx/authed.mjs +1 -1
  167. package/dist/predict/tx/common.d.mts.map +1 -1
  168. package/dist/predict/tx/common.mjs +12 -1
  169. package/dist/predict/tx/common.mjs.map +1 -1
  170. package/dist/predict/tx/queue.d.mts +220 -0
  171. package/dist/predict/tx/queue.d.mts.map +1 -0
  172. package/dist/predict/tx/queue.mjs +399 -0
  173. package/dist/predict/tx/queue.mjs.map +1 -0
  174. package/dist/predict/tx/trade.d.mts.map +1 -1
  175. package/dist/predict/tx/trade.mjs +61 -43
  176. package/dist/predict/tx/trade.mjs.map +1 -1
  177. package/dist/sessions.d.mts +90 -2
  178. package/dist/sessions.d.mts.map +1 -1
  179. package/dist/sessions.mjs +107 -2
  180. package/dist/sessions.mjs.map +1 -1
  181. package/dist/transactions/balanceManager.d.mts +12 -12
  182. package/dist/transactions/balanceManager.d.mts.map +1 -1
  183. package/dist/transactions/deepbook.d.mts +20 -20
  184. package/dist/transactions/deepbook.d.mts.map +1 -1
  185. package/dist/transactions/deepbookAdmin.d.mts +4 -4
  186. package/dist/transactions/deepbookAdmin.d.mts.map +1 -1
  187. package/dist/transactions/marginAdmin.d.mts +7 -7
  188. package/dist/transactions/marginAdmin.d.mts.map +1 -1
  189. package/dist/transactions/marginLiquidations.d.mts +3 -3
  190. package/dist/transactions/marginMaintainer.d.mts +5 -5
  191. package/dist/transactions/marginMaintainer.d.mts.map +1 -1
  192. package/dist/transactions/marginManager.d.mts +32 -32
  193. package/dist/transactions/marginManager.d.mts.map +1 -1
  194. package/dist/transactions/marginPool.d.mts +18 -18
  195. package/dist/transactions/marginRegistry.d.mts +16 -16
  196. package/dist/transactions/marginTPSL.d.mts +10 -10
  197. package/dist/transactions/marginTPSL.d.mts.map +1 -1
  198. package/dist/transactions/poolProxy.d.mts +8 -8
  199. package/dist/transactions/poolProxy.d.mts.map +1 -1
  200. package/package.json +4 -4
  201. package/src/contracts/deepbook_predict/config_events.ts +39 -0
  202. package/src/contracts/deepbook_predict/deps/std/type_name.ts +24 -0
  203. package/src/contracts/deepbook_predict/expiry_market.ts +960 -169
  204. package/src/contracts/deepbook_predict/order_events.ts +3 -1
  205. package/src/contracts/deepbook_predict/plp.ts +150 -9
  206. package/src/contracts/deepbook_predict/pricing.ts +46 -7
  207. package/src/contracts/deepbook_predict/pricing_config.ts +3 -1
  208. package/src/contracts/deepbook_predict/protocol_config.ts +648 -33
  209. package/src/contracts/deepbook_predict/strike_payout_tree.ts +25 -21
  210. package/src/contracts/deepbook_predict/vault_events.ts +65 -0
  211. package/src/contracts/deepbook_predict_math/config-arguments.ts +6 -0
  212. package/src/contracts/deepbook_predict_math/lazer_price.ts +196 -0
  213. package/src/contracts/deepbook_predict_math/math.ts +553 -0
  214. package/src/contracts/deepbook_predict_orders/config-arguments.ts +11 -0
  215. package/src/contracts/deepbook_predict_orders/delayed_execution_config.ts +430 -0
  216. package/src/contracts/deepbook_predict_orders/deps/deepbook_predict/expiry_market.ts +108 -0
  217. package/src/contracts/deepbook_predict_orders/deps/deepbook_predict/pricing.ts +58 -0
  218. package/src/contracts/deepbook_predict_orders/deps/fixed_math/i64.ts +21 -0
  219. package/src/contracts/deepbook_predict_orders/deps/sui/balance.ts +19 -0
  220. package/src/contracts/deepbook_predict_orders/deps/sui/table.ts +37 -0
  221. package/src/contracts/deepbook_predict_orders/desk.ts +419 -0
  222. package/src/contracts/deepbook_predict_orders/order_flow.ts +19 -0
  223. package/src/contracts/deepbook_predict_orders/order_queue.ts +1670 -0
  224. package/src/contracts/deepbook_predict_orders/queue.ts +1394 -0
  225. package/src/contracts/deepbook_predict_orders/queue_events.ts +189 -0
  226. package/src/contracts/deepbook_sessions/sessions.ts +355 -4
  227. package/src/deployments/mainnet.ts +7 -2
  228. package/src/deployments/testnet.ts +7 -2
  229. package/src/deployments/types.ts +14 -1
  230. package/src/predict/bindings/expiry-market.ts +127 -0
  231. package/src/predict/bindings/protocol-config.ts +59 -0
  232. package/src/predict/bindings/rename.ts +14 -0
  233. package/src/predict/client.ts +2076 -13
  234. package/src/predict/config/generated.ts +50 -0
  235. package/src/predict/config/mainnet.ts +16 -2
  236. package/src/predict/config/testnet.ts +16 -2
  237. package/src/predict/config/types.ts +51 -1
  238. package/src/predict/cost.ts +62 -14
  239. package/src/predict/decode.ts +691 -2
  240. package/src/predict/errors.ts +391 -14
  241. package/src/predict/index.ts +87 -6
  242. package/src/predict/queue-id.ts +22 -0
  243. package/src/predict/queue.ts +1231 -0
  244. package/src/predict/reads/markets.ts +30 -0
  245. package/src/predict/reads/queue.ts +606 -0
  246. package/src/predict/ticks.ts +35 -0
  247. package/src/predict/tx/common.ts +25 -1
  248. package/src/predict/tx/queue.ts +525 -0
  249. package/src/predict/tx/trade.ts +80 -49
  250. package/src/sessions.ts +206 -1
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Mysten Labs, Inc.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
+ import { bcs } from '@mysten/sui/bcs';
3
4
  import type { Transaction, TransactionArgument, TransactionResult } from '@mysten/sui/transactions';
5
+ import { deriveObjectID } from '@mysten/sui/utils';
4
6
  import { toGeneratedConfig, type GeneratedConfig } from '../config/generated.js';
5
7
  import type { PredictConfig } from '../config/index.js';
6
8
  import { AccountContract, accountMoveCalls as account } from '../../account.js';
@@ -46,12 +48,14 @@ type NamedArguments<Options extends AuthCallOptions> = Extract<
46
48
  /**
47
49
  * The options {@link withAuth} leaves to the caller: the generated ones, minus the `auth`
48
50
  * argument it supplies itself, with the projected config required (it is what mints the auth).
51
+ * The config must also carry every key the wrapped call resolves, so a call into the order-flow
52
+ * companion can't be handed a slice without its desk.
49
53
  */
50
54
  export type WithAuthOptions<Options extends AuthCallOptions> = Omit<
51
55
  Options,
52
56
  'arguments' | 'config'
53
57
  > & {
54
- config: GeneratedConfig;
58
+ config: GeneratedConfig & NonNullable<Options['config']>;
55
59
  arguments: Omit<NamedArguments<Options>, 'auth'>;
56
60
  };
57
61
 
@@ -90,3 +94,23 @@ export function deriveAccountWrapperIdFrom(
90
94
  export function deriveAccountWrapperId(cfg: PredictConfig, owner: string): string {
91
95
  return deriveAccountWrapperIdFrom(toGeneratedConfig(cfg), owner);
92
96
  }
97
+
98
+ // `account_registry::AccountKey(owner)`: a one-field positional struct, so its BCS is the bare
99
+ // 32-byte address.
100
+ const AccountKey = bcs.struct('AccountKey', { pos0: bcs.Address });
101
+
102
+ /**
103
+ * The owner's canonical ACCOUNT id (`Account.account_id`), a different derived object from the
104
+ * wrapper: `derive_address(registry, AccountKey(owner))`. Queue records and events name accounts
105
+ * by it, and `queue::waiting_orders` takes it.
106
+ */
107
+ export function deriveAccountIdFrom(
108
+ config: Pick<GeneratedConfig, 'accountRegistry' | 'accountPackageId'>,
109
+ owner: string,
110
+ ): string {
111
+ return deriveObjectID(
112
+ config.accountRegistry,
113
+ `${config.accountPackageId}::account_registry::AccountKey`,
114
+ AccountKey.serialize({ pos0: owner }).toBytes(),
115
+ );
116
+ }
@@ -0,0 +1,525 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // Delayed execution (DBU-885): composable thunks for queued orders. Each is
4
+ // `(config, args) => (tx) => result`, like `tx/trade.ts`, so an app can put several into one
5
+ // PTB. The `PredictClient.tx.enqueue*` facade adds the chain preflight on top.
6
+ //
7
+ // Every queued-order entry point lives in the order-flow companion, `deepbook_predict_orders`
8
+ // (`queue::*`), and runs against one market's `MarketQueue` plus the companion's shared
9
+ // `OrderDesk`. The queue's ID is derived from the companion's `QueueRegistry` and the market, so
10
+ // each thunk takes it as an optional `queueId` and derives it otherwise. The thunks take
11
+ // `OrdersGeneratedConfig` (`toOrdersConfig(cfg)`), which supplies the companion package, the desk,
12
+ // the registry and Predict's shared objects.
13
+ //
14
+ // Every call that can send USDC (`resolve`, `refund`, `admin_refund`, `settle_step`, `pay_open`,
15
+ // `claim_parked`) also reads Sui's shared `DenyList` (0x403), which the generated bindings inject
16
+ // as a read-only shared input. Nothing sends USDC to an address on USDC's deny list, or while USDC
17
+ // is globally paused: a fill for such a receive address is refused (reason 9), a refund or change
18
+ // is parked in its record (`RecordFundsParked`), and a payout is skipped until `pay_open`.
19
+ //
20
+ // Queued orders read the oracle objects directly for their volatility snapshot, so unlike the
21
+ // retired immediate trades there is no `load_live_pricer` command before them.
22
+ import type { Transaction, TransactionResult } from '@mysten/sui/transactions';
23
+ import type { GeneratedConfig, OrdersGeneratedConfig } from '../config/generated.js';
24
+ import { MIN_PREMIUM } from '../cost.js';
25
+ import { PredictInputError } from '../errors.js';
26
+ import { deriveQueueId } from '../queue-id.js';
27
+ import { U64_MAX } from '../units.js';
28
+ import * as plp from '../../contracts/deepbook_predict/plp.js';
29
+ import * as delayedExecutionConfig from '../../contracts/deepbook_predict_orders/delayed_execution_config.js';
30
+ import * as desk from '../../contracts/deepbook_predict_orders/desk.js';
31
+ import * as queue from '../../contracts/deepbook_predict_orders/queue.js';
32
+ import { withAuth } from './common.js';
33
+ import type { MarketFeeds } from './trade.js';
34
+
35
+ const FLOAT_SCALING = 1_000_000_000n;
36
+
37
+ // The queued placements with their `auth` argument already supplied: auth → enqueue.
38
+ const authed = {
39
+ enqueueExactQuantity: withAuth(queue.enqueueExactQuantity),
40
+ enqueueExactAmount: withAuth(queue.enqueueExactAmount),
41
+ enqueueExactCost: withAuth(queue.enqueueExactCost),
42
+ enqueueRedeemOpen: withAuth(queue.enqueueRedeemOpen),
43
+ };
44
+
45
+ /** One market's queue. */
46
+ export interface QueueTarget {
47
+ expiryMarketId: string;
48
+ /**
49
+ * The market's `MarketQueue`. Defaults to `deriveQueueId(config.queueRegistry, expiryMarketId)`,
50
+ * the ID `queue::create_and_share` gives it, so pass it only to address another registry's
51
+ * queue.
52
+ */
53
+ queueId?: string;
54
+ }
55
+
56
+ /** The queue ID a thunk addresses: the given one, or the one derived from the config's registry. */
57
+ export function queueIdOf(
58
+ config: Pick<OrdersGeneratedConfig, 'queueRegistry'>,
59
+ args: QueueTarget,
60
+ ): string {
61
+ return args.queueId ?? deriveQueueId(config.queueRegistry, args.expiryMarketId);
62
+ }
63
+
64
+ /** The market, queue and account every queued order names. */
65
+ interface QueuedOrderTarget extends MarketFeeds, QueueTarget {
66
+ wrapperId: string;
67
+ }
68
+
69
+ // The leading arguments every placement shares, after `queue` and `market`.
70
+ function placement(config: OrdersGeneratedConfig, args: QueuedOrderTarget) {
71
+ return {
72
+ queue: queueIdOf(config, args),
73
+ market: args.expiryMarketId,
74
+ wrapper: args.wrapperId,
75
+ pyth: args.pythFeed,
76
+ bsValues: args.blockScholesValueStore,
77
+ bsSvi: args.blockScholesSviStore,
78
+ };
79
+ }
80
+
81
+ // The chain refuses a zero or "unlimited" cap (`EMintCostCapRequired`), so a queued mint always
82
+ // carries a real one. Checked here so a bad cap never reaches a PTB.
83
+ function assertMaxCost(maxCostRaw: bigint): void {
84
+ if (typeof maxCostRaw !== 'bigint' || maxCostRaw <= 0n || maxCostRaw >= U64_MAX) {
85
+ throw new PredictInputError(
86
+ `maxCostRaw must be above 0 and below u64::MAX (a queued mint requires a real cap), got ${String(maxCostRaw)}`,
87
+ );
88
+ }
89
+ }
90
+
91
+ function assertU64(value: bigint, name: string): void {
92
+ if (typeof value !== 'bigint' || value < 0n || value > U64_MAX) {
93
+ throw new PredictInputError(`${name} must be a u64 bigint, got ${String(value)}`);
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Queue a mint of an exact payout quantity, priced at Pyth's signed price for its τ
99
+ * (`queue::enqueue_exact_quantity`). Returns the record ID (u64). `maxCostRaw` (all-in cap) and
100
+ * `maxProbabilityRaw` (entry-probability cap, at most 1e9) are required: there is no "unlimited"
101
+ * default on the queued path. Escrows `min(max_cost, quantity, available − fee)` plus the order
102
+ * fee. Command order is auth → enqueue.
103
+ */
104
+ export function enqueueExactQuantity(
105
+ config: OrdersGeneratedConfig,
106
+ args: QueuedOrderTarget & {
107
+ lowerTick: bigint;
108
+ higherTick: bigint;
109
+ quantityRaw: bigint;
110
+ maxCostRaw: bigint;
111
+ maxProbabilityRaw: bigint;
112
+ },
113
+ ): (tx: Transaction) => TransactionResult {
114
+ assertMaxCost(args.maxCostRaw);
115
+ assertU64(args.quantityRaw, 'quantityRaw');
116
+ if (
117
+ typeof args.maxProbabilityRaw !== 'bigint' ||
118
+ args.maxProbabilityRaw <= 0n ||
119
+ args.maxProbabilityRaw > FLOAT_SCALING
120
+ ) {
121
+ throw new PredictInputError(
122
+ `maxProbabilityRaw must be in (0, 1e9], got ${String(args.maxProbabilityRaw)}`,
123
+ );
124
+ }
125
+ return authed.enqueueExactQuantity({
126
+ config,
127
+ arguments: {
128
+ ...placement(config, args),
129
+ lowerTick: args.lowerTick,
130
+ higherTick: args.higherTick,
131
+ quantity: args.quantityRaw,
132
+ maxCost: args.maxCostRaw,
133
+ maxProbability: args.maxProbabilityRaw,
134
+ },
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Queue a premium-budget mint (`queue::enqueue_exact_amount`): sized at τ under
140
+ * `maxPremiumRaw`, at least `minQuantityRaw`, with the all-in withdrawal capped by the required
141
+ * `maxCostRaw`. Escrows `min(max_cost, available − fee)` plus the order fee. Returns the record
142
+ * ID. Command order is auth → enqueue. `maxPremiumRaw` below the minimum premium (1 USDC) is
143
+ * refused: the fill could never buy enough premium, so Predict's admission dry run would abort
144
+ * `EOrderFailsLimits`.
145
+ */
146
+ export function enqueueExactAmount(
147
+ config: OrdersGeneratedConfig,
148
+ args: QueuedOrderTarget & {
149
+ lowerTick: bigint;
150
+ higherTick: bigint;
151
+ maxPremiumRaw: bigint;
152
+ minQuantityRaw: bigint;
153
+ maxCostRaw: bigint;
154
+ },
155
+ ): (tx: Transaction) => TransactionResult {
156
+ assertMaxCost(args.maxCostRaw);
157
+ assertU64(args.maxPremiumRaw, 'maxPremiumRaw');
158
+ assertU64(args.minQuantityRaw, 'minQuantityRaw');
159
+ if (args.maxPremiumRaw < MIN_PREMIUM) {
160
+ throw new PredictInputError(
161
+ `maxPremiumRaw ${args.maxPremiumRaw} is below the ${MIN_PREMIUM} minimum premium (EOrderFailsLimits)`,
162
+ );
163
+ }
164
+ return authed.enqueueExactAmount({
165
+ config,
166
+ arguments: {
167
+ ...placement(config, args),
168
+ lowerTick: args.lowerTick,
169
+ higherTick: args.higherTick,
170
+ maxPremium: args.maxPremiumRaw,
171
+ minQuantity: args.minQuantityRaw,
172
+ maxCost: args.maxCostRaw,
173
+ },
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Queue an all-in-budget mint (`queue::enqueue_exact_cost`): sized at τ so the all-in cost fits
179
+ * `maxCostRaw`, at least `minQuantityRaw`. `maxCostRaw` is the budget and must be a real cap.
180
+ * Escrows `min(max_cost, available − fee)` plus the order fee. Returns the record ID. Command
181
+ * order is auth → enqueue.
182
+ */
183
+ export function enqueueExactCost(
184
+ config: OrdersGeneratedConfig,
185
+ args: QueuedOrderTarget & {
186
+ lowerTick: bigint;
187
+ higherTick: bigint;
188
+ maxCostRaw: bigint;
189
+ minQuantityRaw: bigint;
190
+ },
191
+ ): (tx: Transaction) => TransactionResult {
192
+ assertMaxCost(args.maxCostRaw);
193
+ assertU64(args.minQuantityRaw, 'minQuantityRaw');
194
+ return authed.enqueueExactCost({
195
+ config,
196
+ arguments: {
197
+ ...placement(config, args),
198
+ lowerTick: args.lowerTick,
199
+ higherTick: args.higherTick,
200
+ maxCost: args.maxCostRaw,
201
+ minQuantity: args.minQuantityRaw,
202
+ },
203
+ });
204
+ }
205
+
206
+ /**
207
+ * Queue an early sell of `closeQuantityRaw` from the Open record `recordId`
208
+ * (`queue::enqueue_redeem_open`; the queue record ID, not the position's u256 order ID). The
209
+ * only early sell: a position held in the account can't be sold early. The record must be Open
210
+ * and belong to this account. `minProbabilityRaw` and `minProceedsRaw` are the close-side floors
211
+ * at τ and are required (`0n` disables either, so pass it on purpose). Escrows only the order
212
+ * fee. Returns the new record ID, which holds the position until the sell fills or refunds.
213
+ * Command order is auth → enqueue.
214
+ */
215
+ export function enqueueRedeemOpen(
216
+ config: OrdersGeneratedConfig,
217
+ args: QueuedOrderTarget & {
218
+ recordId: bigint;
219
+ closeQuantityRaw: bigint;
220
+ minProbabilityRaw: bigint;
221
+ minProceedsRaw: bigint;
222
+ },
223
+ ): (tx: Transaction) => TransactionResult {
224
+ assertU64(args.recordId, 'recordId');
225
+ assertU64(args.minProbabilityRaw, 'minProbabilityRaw');
226
+ assertU64(args.minProceedsRaw, 'minProceedsRaw');
227
+ if (typeof args.closeQuantityRaw !== 'bigint' || args.closeQuantityRaw <= 0n) {
228
+ throw new PredictInputError(
229
+ `closeQuantityRaw must be above 0, got ${String(args.closeQuantityRaw)}`,
230
+ );
231
+ }
232
+ return authed.enqueueRedeemOpen({
233
+ config,
234
+ arguments: {
235
+ ...placement(config, args),
236
+ recordId: args.recordId,
237
+ closeQuantity: args.closeQuantityRaw,
238
+ minProbability: args.minProbabilityRaw,
239
+ minProceeds: args.minProceedsRaw,
240
+ },
241
+ });
242
+ }
243
+
244
+ /**
245
+ * Abort the transaction unless the order desk's fee is at most `maxOrderFeeRaw` when it executes.
246
+ * The enqueues charge the desk's fee at execution and take no fee bound, so add this BEFORE an
247
+ * enqueue to hold it to the fee its preview showed. It reads the desk's policy, and
248
+ * `0x1::u64::checked_sub(max, fee)` is none once the fee is above the bound, so
249
+ * `0x1::option::destroy_some` aborts (`option::EOPTION_NOT_SET`, code 0x40001) before the
250
+ * enqueue debits anything. Read-only on the desk.
251
+ */
252
+ export function assertOrderFeeAtMost(
253
+ config: OrdersGeneratedConfig,
254
+ maxOrderFeeRaw: bigint,
255
+ ): (tx: Transaction) => void {
256
+ assertU64(maxOrderFeeRaw, 'maxOrderFeeRaw');
257
+ return (tx) => {
258
+ const policy = tx.add(desk.policy({ config }));
259
+ const fee = tx.add(delayedExecutionConfig.orderFee({ config, arguments: { policy } }));
260
+ const headroom = tx.moveCall({
261
+ target: '0x1::u64::checked_sub',
262
+ arguments: [tx.pure.u64(maxOrderFeeRaw), fee],
263
+ });
264
+ tx.moveCall({
265
+ target: '0x1::option::destroy_some',
266
+ typeArguments: ['u64'],
267
+ arguments: [headroom],
268
+ });
269
+ };
270
+ }
271
+
272
+ /**
273
+ * Fund a live market from the pool vault to `max(required × (1 + rebalance %), initial cash,
274
+ * required + waiting_cash_need)` (Predict's `plp::rebalance_expiry_cash`). Permissionless, and
275
+ * takes no target. Add it AFTER a big sell's enqueue in the same PTB: the enqueue has already
276
+ * added the sell's cash need to Predict's waiting total, so the rebalance funds it at once. It
277
+ * takes the hot `PoolVault`, so add it only when a sell's cash need is above spare cash.
278
+ */
279
+ export function rebalanceExpiryCash(
280
+ config: GeneratedConfig,
281
+ args: { expiryMarketId: string },
282
+ ): (tx: Transaction) => TransactionResult {
283
+ return plp.rebalanceExpiryCash({ config, arguments: { market: args.expiryMarketId } });
284
+ }
285
+
286
+ /**
287
+ * Create and share a market's `MarketQueue` (`queue::create_and_share(registry, desk, market)`),
288
+ * at the ID `deriveQueueId(config.queueRegistry, expiryMarketId)`. Takes the registry mutably and
289
+ * the desk read-only, so it never contends with trading. Permissionless and once per market (a
290
+ * second call aborts, since the ID is taken); the caller pays its storage. The market-creation
291
+ * keeper sends it after each new `ExpiryMarket`. Returns the queue ID.
292
+ */
293
+ export function createQueue(
294
+ config: OrdersGeneratedConfig,
295
+ args: { expiryMarketId: string },
296
+ ): (tx: Transaction) => TransactionResult {
297
+ return queue.createAndShare({ config, arguments: { market: args.expiryMarketId } });
298
+ }
299
+
300
+ /**
301
+ * Refund this market's waiting orders at or past their deadline (`queue::refund`, reason 5),
302
+ * visiting at most `maxOrders` records (the chain caps one call at 450). Permissionless: no auth,
303
+ * session or Pyth key, and it works during a freeze. Returns how many it refunded, `0` without
304
+ * aborting when none is due. Send it only from the app's refund button, never prepended to other
305
+ * transactions: keepers refund on their own. Every visited record counts toward Sui's
306
+ * per-transaction object limit.
307
+ */
308
+ export function refund(
309
+ config: OrdersGeneratedConfig,
310
+ args: QueueTarget & { maxOrders: bigint | number },
311
+ ): (tx: Transaction) => TransactionResult {
312
+ return queue.refund({
313
+ config,
314
+ arguments: {
315
+ queue: queueIdOf(config, args),
316
+ market: args.expiryMarketId,
317
+ maxOrders: args.maxOrders,
318
+ },
319
+ });
320
+ }
321
+
322
+ /**
323
+ * Refund the listed waiting orders at once (`queue::admin_refund`, reason 7), wherever they sit
324
+ * in the queue. Takes Predict's `AdminCap`, and works while Predict is frozen. Missing and
325
+ * finished record IDs are skipped.
326
+ */
327
+ export function adminRefund(
328
+ config: OrdersGeneratedConfig,
329
+ args: QueueTarget & { adminCapId: string; recordIds: readonly bigint[] },
330
+ ): (tx: Transaction) => TransactionResult {
331
+ return queue.adminRefund({
332
+ config,
333
+ arguments: {
334
+ queue: queueIdOf(config, args),
335
+ market: args.expiryMarketId,
336
+ AdminCap: args.adminCapId,
337
+ recordIds: [...args.recordIds],
338
+ },
339
+ });
340
+ }
341
+
342
+ /**
343
+ * Delete Refunded and Closed records of a settled market (`queue::cleanup`). Permissionless; the
344
+ * storage rebate goes to the sender. Missing IDs, other statuses and records still holding a
345
+ * receipt or funds (parked funds included, until `claimParked`) are skipped. Aborts
346
+ * `EMarketNotSettled` before settlement.
347
+ */
348
+ export function cleanup(
349
+ config: OrdersGeneratedConfig,
350
+ args: QueueTarget & { recordIds: readonly bigint[] },
351
+ ): (tx: Transaction) => TransactionResult {
352
+ return queue.cleanup({
353
+ config,
354
+ arguments: {
355
+ queue: queueIdOf(config, args),
356
+ market: args.expiryMarketId,
357
+ recordIds: [...args.recordIds],
358
+ },
359
+ });
360
+ }
361
+
362
+ /**
363
+ * Run one bounded settlement phase on a market's queue (`queue::settle_step`) and return the
364
+ * phase the queue is in afterwards (u8, `queue.SETTLE_PHASE`): `0` DRAIN refunds the waiting
365
+ * orders, `1` PAY pays the Open records once Predict has settled the market, `2` DONE once the
366
+ * payout walk has reached the last record. Send one call per transaction until it returns `2` (or
367
+ * `MarketPayoutsCompleted` is emitted), after Predict's `try_settle`. A record the market couldn't
368
+ * pay stays Open with `OpenRecordPayoutSkipped`, even after DONE. Permissionless. Aborts
369
+ * `EMarketNotExpired` before expiry.
370
+ */
371
+ export function settleStep(
372
+ config: OrdersGeneratedConfig,
373
+ args: QueueTarget,
374
+ ): (tx: Transaction) => TransactionResult {
375
+ return queue.settleStep({
376
+ config,
377
+ arguments: { queue: queueIdOf(config, args), market: args.expiryMarketId },
378
+ });
379
+ }
380
+
381
+ /**
382
+ * Pay one Open record of a settled market its settled payout (`queue::pay_open`), at any time
383
+ * after settlement, before or after `settle_step` completes: a record the payout walk skipped
384
+ * because the market was short of cash or its receive address was denied. Permissionless: the
385
+ * payout goes only to the record's own receive address. Emits `OpenRecordSettled`, or
386
+ * `OpenRecordPayoutSkipped` again while the cause persists. A missing or non-Open record is left
387
+ * alone. Aborts `EMarketNotSettled` before Predict settles the market.
388
+ */
389
+ export function payOpen(
390
+ config: OrdersGeneratedConfig,
391
+ args: QueueTarget & { recordId: bigint },
392
+ ): (tx: Transaction) => TransactionResult {
393
+ assertU64(args.recordId, 'recordId');
394
+ return queue.payOpen({
395
+ config,
396
+ arguments: {
397
+ queue: queueIdOf(config, args),
398
+ market: args.expiryMarketId,
399
+ recordId: args.recordId,
400
+ },
401
+ });
402
+ }
403
+
404
+ /**
405
+ * Send a finished record's parked funds (`queue::claim_parked`): change or a refund its receive
406
+ * address couldn't take while it was on USDC's deny list or USDC was paused. Permissionless: the
407
+ * funds go only to the record's own receive address. Returns the amount sent (u64), or `0` and
408
+ * changes nothing for a missing or unfinished record, one with nothing parked, or an address still
409
+ * denied. Emits `RecordFundsClaimed`. Takes no market: `expiryMarketId` only derives the queue.
410
+ */
411
+ export function claimParked(
412
+ config: OrdersGeneratedConfig,
413
+ args: QueueTarget & { recordId: bigint },
414
+ ): (tx: Transaction) => TransactionResult {
415
+ assertU64(args.recordId, 'recordId');
416
+ return queue.claimParked({
417
+ config,
418
+ arguments: { queue: queueIdOf(config, args), recordId: args.recordId },
419
+ });
420
+ }
421
+
422
+ /** The current Pyth Lazer package and the original ID that types its `Update`. */
423
+ export interface LazerPackages {
424
+ /** Lazer's shared `State`. */
425
+ stateId: string;
426
+ /** The package to call `parse_and_verify_le_ecdsa_update` on: `State.upgrade_cap.package`. */
427
+ packageId: string;
428
+ /** The original package ID, which `update::Update` is typed by. */
429
+ originalId: string;
430
+ }
431
+
432
+ /**
433
+ * Verify one signed Lazer payload with the current Lazer package. A positional call on purpose:
434
+ * the oracle-construction packages are not generated (see `sui-codegen.config.ts`).
435
+ */
436
+ export function parseLazerUpdate(
437
+ lazer: Pick<LazerPackages, 'stateId' | 'packageId'>,
438
+ payload: Uint8Array,
439
+ ): (tx: Transaction) => TransactionResult {
440
+ return (tx) =>
441
+ tx.moveCall({
442
+ target: `${lazer.packageId}::pyth_lazer::parse_and_verify_le_ecdsa_update`,
443
+ arguments: [tx.object(lazer.stateId), tx.object.clock(), tx.pure.vector('u8', payload)],
444
+ });
445
+ }
446
+
447
+ /**
448
+ * Verify the signed Lazer payloads and commit them to the market's waiting cohorts
449
+ * (`queue::commit`). Permissionless. Pass the payloads for a cohort's exact τ, or a backup tick
450
+ * once τ + gap wait has passed with τ uncommitted (when the policy's price buffer is on). Commit
451
+ * matches each update to its own cohort by τ and skips one that matches nothing, so no
452
+ * head-of-line ordering is assumed. Resolve `lazer` per batch with `read.lazerPackages` and never
453
+ * cache it: a Pyth upgrade retires the old package at once.
454
+ */
455
+ export function commit(
456
+ config: OrdersGeneratedConfig,
457
+ args: QueueTarget & { payloads: readonly Uint8Array[]; lazer: LazerPackages },
458
+ ): (tx: Transaction) => TransactionResult {
459
+ if (args.payloads.length === 0) {
460
+ throw new PredictInputError('commit needs at least one signed Lazer payload');
461
+ }
462
+ return (tx) => {
463
+ const updates = args.payloads.map((payload) => tx.add(parseLazerUpdate(args.lazer, payload)));
464
+ const vector = tx.makeMoveVec({
465
+ type: `${args.lazer.originalId}::update::Update`,
466
+ elements: updates,
467
+ });
468
+ return tx.add(
469
+ queue.commit({
470
+ config,
471
+ arguments: { queue: queueIdOf(config, args), market: args.expiryMarketId, updates: vector },
472
+ }),
473
+ );
474
+ };
475
+ }
476
+
477
+ /**
478
+ * Fill or refund committed orders in τ order (`queue::resolve`), visiting at most `maxOrders`
479
+ * records (the chain caps one call at 450, since a fill emits two events and Sui allows 1,024
480
+ * per transaction). Permissionless. Returns how many orders it finished. An order the market
481
+ * can't cover is refunded with reason 8. Size `maxOrders` against the payout tree
482
+ * (`payoutTreeNodeCount`): about 10 to 15 fills fit one transaction in a full tree.
483
+ */
484
+ export function resolve(
485
+ config: OrdersGeneratedConfig,
486
+ args: QueueTarget & { maxOrders: bigint | number },
487
+ ): (tx: Transaction) => TransactionResult {
488
+ return queue.resolve({
489
+ config,
490
+ arguments: {
491
+ queue: queueIdOf(config, args),
492
+ market: args.expiryMarketId,
493
+ maxOrders: args.maxOrders,
494
+ },
495
+ });
496
+ }
497
+
498
+ /**
499
+ * The open filler (no cap exists): {@link commit} the signed Lazer payloads, then
500
+ * {@link resolve} up to `maxOrders` records. Anyone with Pyth Lazer access can run it. With
501
+ * `refundOverdue`, a final `refund` call sweeps orders past their deadline. Returns the resolve
502
+ * result. Split commit from resolve when the payout tree is large.
503
+ */
504
+ export function fill(
505
+ config: OrdersGeneratedConfig,
506
+ args: QueueTarget & {
507
+ payloads: readonly Uint8Array[];
508
+ lazer: LazerPackages;
509
+ maxOrders: bigint | number;
510
+ refundOverdue?: boolean;
511
+ },
512
+ ): (tx: Transaction) => TransactionResult {
513
+ if (args.payloads.length === 0) {
514
+ throw new PredictInputError('fill needs at least one signed Lazer payload');
515
+ }
516
+ const target = { expiryMarketId: args.expiryMarketId, queueId: queueIdOf(config, args) };
517
+ return (tx) => {
518
+ tx.add(commit(config, { ...target, payloads: args.payloads, lazer: args.lazer }));
519
+ const resolved = tx.add(resolve(config, { ...target, maxOrders: args.maxOrders }));
520
+ if (args.refundOverdue) {
521
+ tx.add(refund(config, { ...target, maxOrders: args.maxOrders }));
522
+ }
523
+ return resolved;
524
+ };
525
+ }