af_iperps/lib.rs
1#![cfg_attr(all(doc, not(doctest)), feature(doc_auto_cfg))]
2
3//! Move types for Aftermath's `Perpetuals` package
4
5use af_move_type::otw::Otw;
6use af_sui_pkg_sdk::sui_pkg_sdk;
7use af_sui_types::{Address, IdentStr, ObjectId, SUI_FRAMEWORK_ADDRESS, object_id};
8use af_utilities::types::ifixed::IFixed;
9use sui_framework_sdk::balance::Balance;
10use sui_framework_sdk::dynamic_object_field::Wrapper;
11use sui_framework_sdk::object::{ID, UID};
12use sui_framework_sdk::sui::SUI;
13use sui_framework_sdk::{Field, FieldTypeTag};
14
15pub mod errors;
16pub mod event_ext;
17pub mod event_instance;
18#[cfg(feature = "graphql")]
19pub mod graphql;
20pub mod math;
21pub mod order_helpers;
22pub mod order_id;
23#[cfg(feature = "stop-orders")]
24pub mod stop_order_helpers;
25
26pub use self::market::{MarketParams, MarketState};
27pub use self::orderbook::Order;
28pub use self::position::Position;
29
30/// Package IDs of the perpetuals contract versions published on testnet, in order of its versions.
31pub const TESTNET_PACKAGE_VERSIONS: &[ObjectId] = &[object_id(
32 b"0x1fc71972750d0d81567183a8500befef94d7699aac76edffcca253fe541367fd",
33)];
34
35// Convenient aliases since these types will never exist onchain with a type argument other than an
36// OTW.
37pub type Account = self::account::Account<Otw>;
38pub type AccountTypeTag = self::account::AccountTypeTag<Otw>;
39pub type StopOrderTicket = self::stop_orders::StopOrderTicket<Otw>;
40pub type StopOrderTicketTypetag = self::stop_orders::StopOrderTicketTypeTag<Otw>;
41pub type ClearingHouse = self::clearing_house::ClearingHouse<Otw>;
42pub type ClearingHouseTypeTag = self::clearing_house::ClearingHouseTypeTag<Otw>;
43pub type SubAccount = self::subaccount::SubAccount<Otw>;
44pub type SubAccountTypeTag = self::subaccount::SubAccountTypeTag<Otw>;
45pub type Vault = self::clearing_house::Vault<Otw>;
46pub type VaultTypeTag = self::clearing_house::VaultTypeTag<Otw>;
47
48/// Dynamic field storing a [`Position`].
49pub type PositionDf = Field<self::keys::Position, Position>;
50/// Dynamic field storing a leaf in a [`Map`] of [`Order`]s.
51///
52/// [`Map`]: self::ordered_map::Map
53pub type OrderLeafDf = Field<u64, self::ordered_map::Leaf<Order>>;
54/// Dynamic object field wrapper for the [`Orderbook`](orderbook::Orderbook) ID.
55pub type OrderbookDofWrapper = Field<Wrapper<keys::Orderbook>, ID>;
56/// Dynamic object field wrapper for the asks [`Map`](ordered_map::Map) ID.
57pub type AsksMapDofWrapper = Field<Wrapper<keys::AsksMap>, ID>;
58/// Dynamic object field wrapper for the bids [`Map`](ordered_map::Map) ID.
59pub type BidsMapDofWrapper = Field<Wrapper<keys::BidsMap>, ID>;
60
61sui_pkg_sdk!(perpetuals {
62 module account {
63 /// The Account object saves the collateral available to be used in clearing houses.
64 struct Account<!phantom T> has key, store {
65 id: UID,
66 /// Numerical value associated to the account
67 account_id: u64,
68 /// Balance available to be allocated to markets.
69 collateral: Balance<T>,
70 }
71 }
72
73 module admin {
74 /// Capability object required to perform admin functions.
75 ///
76 /// Minted once when the module is published and transfered to its creator.
77 struct AdminCapability has key, store {
78 id: UID
79 }
80 }
81
82 module clearing_house {
83 /// The central object that owns the market state.
84 ///
85 /// Dynamic fields:
86 /// - [`position::Position`]
87 /// - [`Vault`]
88 ///
89 /// Dynamic objects:
90 /// - [`orderbook::Orderbook`]
91 struct ClearingHouse<!phantom T> has key {
92 id: UID,
93 version: u64,
94 market_params: market::MarketParams,
95 market_state: market::MarketState
96 }
97
98 /// Stores all deposits from traders for collateral T.
99 /// Stores the funds reserved for covering bad debt from untimely
100 /// liquidations.
101 ///
102 /// The Clearing House keeps track of who owns each share of the vault.
103 struct Vault<!phantom T> has store {
104 collateral_balance: Balance<T>,
105 insurance_fund_balance: Balance<T>,
106 }
107
108 /// Stores the proposed parameters for updating margin ratios
109 struct MarginRatioProposal has store {
110 /// Target timestamp at which to apply the proposed updates
111 maturity: u64,
112 /// Proposed IMR
113 margin_ratio_initial: IFixed,
114 /// Proposed MMR
115 margin_ratio_maintenance: IFixed,
116 }
117
118 /// Stores the proposed parameters for a position's custom fees
119 struct PositionFeesProposal has store {
120 /// Proposed IMR
121 maker_fee: IFixed,
122 /// Proposed MMR
123 taker_fee: IFixed,
124 }
125
126 /// Used by clearing house to check margin when placing an order
127 struct SessionHotPotato<!phantom T> {
128 clearing_house: ClearingHouse<T>,
129 orderbook: orderbook::Orderbook,
130 account_id: u64,
131 timestamp_ms: u64,
132 collateral_price: IFixed,
133 index_price: IFixed,
134 margin_before: IFixed,
135 min_margin_before: IFixed,
136 position_base_before: IFixed,
137 total_open_interest: IFixed,
138 total_fees: IFixed,
139 maker_events: vector<events::FilledMakerOrder>,
140 liquidation_receipt: Option<LiquidationReceipt>,
141 session_summary: SessionSummary
142 }
143
144 struct LiquidationReceipt has drop, store {
145 liqee_account_id: u64,
146 size_to_liquidate: u64,
147 base_ask_cancel: u64,
148 base_bid_cancel: u64,
149 pending_orders: u64
150 }
151
152 struct SessionSummary has drop {
153 base_filled_ask: IFixed,
154 base_filled_bid: IFixed,
155 quote_filled_ask: IFixed,
156 quote_filled_bid: IFixed,
157 base_posted_ask: IFixed,
158 base_posted_bid: IFixed,
159 posted_orders: u64,
160 base_liquidated: IFixed,
161 quote_liquidated: IFixed,
162 is_liqee_long: bool,
163 bad_debt: IFixed
164 }
165 }
166
167 module stop_orders {
168 /// Object that allows to place one order on behalf of the user, used to
169 /// offer stop limit or market orders. A stop order is an order that is placed
170 /// only if the index price respects certain conditions, like being above or
171 /// below a certain price.
172 ///
173 /// Only the `SubAccount` owner can mint this object and can decide who can be
174 /// the executor of the ticket. This allows users to run their
175 /// own stop orders bots eventually, but it's mainly used to allow 3rd parties
176 /// to offer such a service (the user is required to trust such 3rd party).
177 /// The object is shared and the 3rd party is set as `executor`. The ticket
178 /// can be destroyed in any moment only by the user or by the executor.
179 /// The user needs to trust the 3rd party for liveness of the service offered.
180 ///
181 /// The order details are encrypted offchain and the result is stored in the ticket.
182 /// The user needs to share such details with the 3rd party only to allow for execution.
183 struct StopOrderTicket<!phantom T> has key {
184 id: UID,
185 /// Addresses allowed to execute the order on behalf of the user.
186 executors: vector<address>,
187 /// Gas coin that must be provided by the user to cover for one stop order cost.
188 /// This amount of gas is going to be sent to the executor of the order.
189 gas: Balance<SUI>,
190 /// User account id
191 account_id: u64,
192 /// Value to indentify the stop order type. Available values can be found in the
193 /// constants module.
194 stop_order_type: u64,
195 /// Vector containing the blake2b hash obtained from offchain on the stop order parameters.
196 /// Depending on the stop order type value, a different set of parameters is expected to be used.
197 ///
198 /// Parameters encoded for a SLTP stop order (stop_order_type code 0):
199 /// - clearing_house_id: ID
200 /// - expire_timestamp: Option<u64>
201 /// - is_limit_order: `true` if limit order, `false` if market order
202 /// - stop_index_price: u256
203 /// - is_stop_loss: `true` if stop loss order, `false` if take profit order
204 /// - position_is_ask: `true` if position is short, `false` if position is long
205 /// - size: u64
206 /// - price: u64 (can be set at random value if `is_limit_order` is false)
207 /// - order_type: u64 (can be set at random value if `is_limit_order` is false)
208 /// - salt: vector<u8>
209 ///
210 /// Parameters encoded for a Standalone stop order (stop_order_type code 1):
211 /// - clearing_house_id: ID
212 /// - expire_timestamp: Option<u64>
213 /// - is_limit_order: `true` if limit order, `false` if market order
214 /// - stop_index_price: u256
215 /// - ge_stop_index_price: `true` means the order can be placed when
216 /// oracle index price is >= than chosen `stop_index_price`
217 /// - side: bool
218 /// - size: u64
219 /// - price: u64 (can be set at random value if `is_limit_order` is false)
220 /// - order_type: u64 (can be set at random value if `is_limit_order` is false)
221 /// - reduce_only: bool
222 /// - salt: vector<u8>
223 encrypted_details: vector<u8>
224 }
225 }
226
227 module subaccount {
228 /// The SubAccount object represents a shared version of the `Account` object
229 /// with limited access to protocol's features. Being a shared object, it can
230 /// only be used by the addresses specified in the `users` field.
231 /// Only the parent Account can withdraw Coin from a subaccount. The parent account is
232 /// required to specify a Sui address that will be able to use the subaccount on its behalf
233 /// and can change this address at any moment.
234 ///
235 /// Subaccounts are used for trading and depositing, without running into race conditions, i.e.,
236 /// concurrent transactions using the same subaccount can be created and submitted (unlike
237 /// accounts).
238 ///
239 /// The created subaccount will share the primary's account_id. That means it has access to the
240 /// same positions of the primary.
241 ///
242 /// The subaccount's users are then able to:
243 /// - deposit collateral into the subaccount
244 /// - allocate collateral from subaccount to a clearing house
245 /// - use session to trade and liquidate on clearing house
246 /// - cancel pending orders
247 /// - deallocate from a clearing house to a subaccount
248 struct SubAccount<!phantom T> has key, store {
249 id: UID,
250 /// Addresses able to make calls using this `SubAccount`
251 users: vector<address>,
252 /// Numerical value associated to the parent account
253 account_id: u64,
254 /// Balance available to be allocated to markets.
255 collateral: Balance<T>,
256 }
257 }
258
259 module events {
260 struct CreatedAccount<!phantom T> has copy, drop {
261 user: address,
262 account_id: u64
263 }
264
265 struct DepositedCollateral<!phantom T> has copy, drop {
266 account_id: u64,
267 subaccount_id: Option<ID>,
268 collateral: u64,
269 }
270
271 struct AllocatedCollateral has copy, drop {
272 ch_id: ID,
273 account_id: u64,
274 subaccount_id: Option<ID>,
275 collateral: u64,
276 }
277
278 struct WithdrewCollateral<!phantom T> has copy, drop {
279 account_id: u64,
280 subaccount_id: Option<ID>,
281 collateral: u64,
282 }
283
284 struct DeallocatedCollateral has copy, drop {
285 ch_id: ID,
286 account_id: u64,
287 subaccount_id: Option<ID>,
288 collateral: u64,
289 }
290
291 struct CreatedOrderbook has copy, drop {
292 branch_min: u64,
293 branches_merge_max: u64,
294 branch_max: u64,
295 leaf_min: u64,
296 leaves_merge_max: u64,
297 leaf_max: u64
298 }
299
300 struct CreatedClearingHouse has copy, drop {
301 ch_id: ID,
302 collateral: String,
303 coin_decimals: u64,
304 margin_ratio_initial: IFixed,
305 margin_ratio_maintenance: IFixed,
306 base_oracle_id: ID,
307 collateral_oracle_id: ID,
308 funding_frequency_ms: u64,
309 funding_period_ms: u64,
310 premium_twap_frequency_ms: u64,
311 premium_twap_period_ms: u64,
312 spread_twap_frequency_ms: u64,
313 spread_twap_period_ms: u64,
314 maker_fee: IFixed,
315 taker_fee: IFixed,
316 liquidation_fee: IFixed,
317 force_cancel_fee: IFixed,
318 insurance_fund_fee: IFixed,
319 lot_size: u64,
320 tick_size: u64,
321 }
322
323 struct RegisteredMarketInfo<!phantom T> has copy, drop {
324 ch_id: ID,
325 base_pfs_id: ID,
326 collateral_pfs_id: ID,
327 lot_size: u64,
328 tick_size: u64,
329 scaling_factor: IFixed
330 }
331
332 struct RemovedRegisteredMarketInfo<!phantom T> has copy, drop {
333 ch_id: ID,
334 }
335
336 struct RegisteredCollateralInfo<!phantom T> has copy, drop {
337 ch_id: ID,
338 collateral_pfs_id: ID,
339 scaling_factor: IFixed
340 }
341
342 struct UpdatedClearingHouseVersion has copy, drop {
343 ch_id: ID,
344 version: u64
345 }
346
347 struct UpdatedPremiumTwap has copy, drop {
348 ch_id: ID,
349 book_price: IFixed,
350 index_price: IFixed,
351 premium_twap: IFixed,
352 premium_twap_last_upd_ms: u64,
353 }
354
355 struct UpdatedSpreadTwap has copy, drop {
356 ch_id: ID,
357 book_price: IFixed,
358 index_price: IFixed,
359 spread_twap: IFixed,
360 spread_twap_last_upd_ms: u64,
361 }
362
363 struct UpdatedFunding has copy, drop {
364 ch_id: ID,
365 cum_funding_rate_long: IFixed,
366 cum_funding_rate_short: IFixed,
367 funding_last_upd_ms: u64,
368 }
369
370 struct SettledFunding has copy, drop {
371 ch_id: ID,
372 account_id: u64,
373 collateral_change_usd: IFixed,
374 collateral_after: IFixed,
375 mkt_funding_rate_long: IFixed,
376 mkt_funding_rate_short: IFixed
377 }
378
379 struct FilledMakerOrders has copy, drop {
380 events: vector<FilledMakerOrder>
381 }
382
383 struct FilledMakerOrder has copy, drop {
384 ch_id: ID,
385 maker_account_id: u64,
386 taker_account_id: u64,
387 order_id: u128,
388 filled_size: u64,
389 remaining_size: u64,
390 canceled_size: u64,
391 pnl: IFixed,
392 fees: IFixed,
393 }
394
395 struct FilledTakerOrder has copy, drop {
396 ch_id: ID,
397 taker_account_id: u64,
398 taker_pnl: IFixed,
399 taker_fees: IFixed,
400 base_asset_delta_ask: IFixed,
401 quote_asset_delta_ask: IFixed,
402 base_asset_delta_bid: IFixed,
403 quote_asset_delta_bid: IFixed,
404 }
405
406 struct PostedOrder has copy, drop {
407 ch_id: ID,
408 account_id: u64,
409 order_id: u128,
410 order_size: u64,
411 reduce_only: bool,
412 expiration_timestamp_ms: Option<u64>
413 }
414
415 struct CanceledOrder has copy, drop {
416 ch_id: ID,
417 account_id: u64,
418 size: u64,
419 order_id: u128,
420 }
421
422 struct LiquidatedPosition has copy, drop {
423 ch_id: ID,
424 liqee_account_id: u64,
425 liqor_account_id: u64,
426 is_liqee_long: bool,
427 base_liquidated: IFixed,
428 quote_liquidated: IFixed,
429 liqee_pnl: IFixed,
430 liquidation_fees: IFixed,
431 force_cancel_fees: IFixed,
432 insurance_fund_fees: IFixed,
433 bad_debt: IFixed
434 }
435
436 struct PerformedLiquidation has copy, drop {
437 ch_id: ID,
438 liqee_account_id: u64,
439 liqor_account_id: u64,
440 is_liqee_long: bool,
441 base_liquidated: IFixed,
442 quote_liquidated: IFixed,
443 liqor_pnl: IFixed,
444 liqor_fees: IFixed,
445 }
446
447 struct UpdatedCumFundings has copy, drop {
448 ch_id: ID,
449 cum_funding_rate_long: IFixed,
450 cum_funding_rate_short: IFixed,
451 }
452
453 struct CreatedPosition has copy, drop {
454 ch_id: ID,
455 account_id: u64,
456 subaccount_id: Option<ID>,
457 mkt_funding_rate_long: IFixed,
458 mkt_funding_rate_short: IFixed,
459 }
460
461 struct SetPositionInitialMarginRatio has copy, drop {
462 ch_id: ID,
463 account_id: u64,
464 initial_margin_ratio: IFixed,
465 }
466
467 struct CreatedStopOrderTicket<!phantom T> has copy, drop {
468 ticket_id: ID,
469 account_id: u64,
470 subaccount_id: Option<ID>,
471 executors: vector<address>,
472 gas: u64,
473 stop_order_type: u64,
474 encrypted_details: vector<u8>
475 }
476
477 struct ExecutedStopOrderTicket<!phantom T> has copy, drop {
478 ticket_id: ID,
479 account_id: u64,
480 executor: address
481 }
482
483 struct DeletedStopOrderTicket<!phantom T> has copy, drop {
484 ticket_id: ID,
485 account_id: u64,
486 subaccount_id: Option<ID>,
487 executor: address
488 }
489
490 struct EditedStopOrderTicketDetails<!phantom T> has copy, drop {
491 ticket_id: ID,
492 account_id: u64,
493 subaccount_id: Option<ID>,
494 stop_order_type: u64,
495 encrypted_details: vector<u8>
496 }
497
498 struct EditedStopOrderTicketExecutors<!phantom T> has copy, drop {
499 ticket_id: ID,
500 account_id: u64,
501 subaccount_id: Option<ID>,
502 executors: vector<address>
503 }
504
505 struct CreatedMarginRatiosProposal has copy, drop {
506 ch_id: ID,
507 margin_ratio_initial: IFixed,
508 margin_ratio_maintenance: IFixed,
509 }
510
511 struct UpdatedMarginRatios has copy, drop {
512 ch_id: ID,
513 margin_ratio_initial: IFixed,
514 margin_ratio_maintenance: IFixed,
515 }
516
517 struct DeletedMarginRatiosProposal has copy, drop {
518 ch_id: ID,
519 margin_ratio_initial: IFixed,
520 margin_ratio_maintenance: IFixed,
521 }
522
523 struct CreatedPositionFeesProposal has copy, drop {
524 ch_id: ID,
525 account_id: u64,
526 maker_fee: IFixed,
527 taker_fee: IFixed,
528 }
529
530 struct DeletedPositionFeesProposal has copy, drop {
531 ch_id: ID,
532 account_id: u64,
533 maker_fee: IFixed,
534 taker_fee: IFixed,
535 }
536
537 struct AcceptedPositionFeesProposal has copy, drop {
538 ch_id: ID,
539 account_id: u64,
540 maker_fee: IFixed,
541 taker_fee: IFixed,
542 }
543
544 struct RejectedPositionFeesProposal has copy, drop {
545 ch_id: ID,
546 account_id: u64,
547 maker_fee: IFixed,
548 taker_fee: IFixed,
549 }
550
551 struct ResettedPositionFees has copy, drop {
552 ch_id: ID,
553 account_id: u64,
554 }
555
556 struct UpdatedFees has copy, drop {
557 ch_id: ID,
558 maker_fee: IFixed,
559 taker_fee: IFixed,
560 liquidation_fee: IFixed,
561 force_cancel_fee: IFixed,
562 insurance_fund_fee: IFixed,
563 }
564
565 struct UpdatedFundingParameters has copy, drop {
566 ch_id: ID,
567 funding_frequency_ms: u64,
568 funding_period_ms: u64,
569 premium_twap_frequency_ms: u64,
570 premium_twap_period_ms: u64,
571 }
572
573 struct UpdatedSpreadTwapParameters has copy, drop {
574 ch_id: ID,
575 spread_twap_frequency_ms: u64,
576 spread_twap_period_ms: u64
577 }
578
579 struct UpdatedMinOrderUsdValue has copy, drop {
580 ch_id: ID,
581 min_order_usd_value: IFixed,
582 }
583
584 struct UpdatedLiquidationTolerance has copy, drop {
585 ch_id: ID,
586 liquidation_tolerance: u64,
587 }
588
589 struct UpdatedBaseOracleTolerance has copy, drop {
590 ch_id: ID,
591 oracle_tolerance: u64,
592 }
593
594 struct UpdatedCollateralOracleTolerance has copy, drop {
595 ch_id: ID,
596 oracle_tolerance: u64,
597 }
598
599 struct UpdatedMaxOpenInterest has copy, drop {
600 ch_id: ID,
601 max_open_interest: IFixed,
602 }
603
604 struct UpdatedMaxOpenInterestPositionParams has copy, drop {
605 ch_id: ID,
606 max_open_interest_threshold: IFixed,
607 max_open_interest_position_percent: IFixed,
608 }
609
610 struct UpdatedMaxPendingOrders has copy, drop {
611 ch_id: ID,
612 max_pending_orders: u64
613 }
614
615 struct UpdatedStopOrderMistCost has copy, drop {
616 stop_order_mist_cost: u64
617 }
618
619 struct DonatedToInsuranceFund has copy, drop {
620 sender: address,
621 ch_id: ID,
622 new_balance: u64,
623 }
624
625 struct WithdrewFees has copy, drop {
626 sender: address,
627 ch_id: ID,
628 amount: u64,
629 vault_balance_after: u64,
630 }
631
632 struct WithdrewInsuranceFund has copy, drop {
633 sender: address,
634 ch_id: ID,
635 amount: u64,
636 insurance_fund_balance_after: u64,
637 }
638
639 struct UpdatedOpenInterestAndFeesAccrued has copy, drop {
640 ch_id: ID,
641 open_interest: IFixed,
642 fees_accrued: IFixed
643 }
644
645 struct CreatedSubAccount has copy, drop {
646 subaccount_id: ID,
647 users: vector<address>,
648 account_id: u64
649 }
650
651 struct SetSubAccountUsers has copy, drop {
652 subaccount_id: ID,
653 users: vector<address>,
654 account_id: u64
655 }
656 }
657
658 module keys {
659 /// Key type for accessing a `MarketInfo` saved in registry.
660 struct RegistryMarketInfo has copy, drop, store {
661 ch_id: ID
662 }
663
664 /// Key type for accessing a `CollateralInfo` saved in registry.
665 struct RegistryCollateralInfo<!phantom T> has copy, drop, store {}
666
667 /// Key type for accessing a `Config` saved in registry.
668 struct RegistryConfig has copy, drop, store {}
669
670 /// Key type for accessing market params in clearing house.
671 struct Orderbook has copy, drop, store {}
672
673 /// Key type for accessing vault in clearing house.
674 struct MarketVault has copy, drop, store {}
675
676 /// Key type for accessing trader position in clearing house.
677 struct Position has copy, drop, store {
678 account_id: u64,
679 }
680
681 /// Key type for accessing market margin parameters change proposal in clearing house.
682 struct MarginRatioProposal has copy, drop, store {}
683
684 /// Key type for accessing custom fees parameters change proposal for an account
685 struct PositionFeesProposal has copy, drop, store {
686 account_id: u64
687 }
688
689 /// Key type for accessing asks map in the orderbook
690 struct AsksMap has copy, drop, store {}
691
692 /// Key type for accessing asks map in the orderbook
693 struct BidsMap has copy, drop, store {}
694 }
695
696 module market {
697 /// Static attributes of a perpetuals market.
698 struct MarketParams has copy, drop, store {
699 /// Minimum margin ratio for opening a new position.
700 margin_ratio_initial: IFixed,
701 /// Margin ratio below which full liquidations can occur.
702 margin_ratio_maintenance: IFixed,
703 /// Identifier of the base asset's price feed storage.
704 base_pfs_id: ID,
705 /// Identifier of the collateral asset's price feed storage.
706 collateral_pfs_id: ID,
707 /// The time span between each funding rate update.
708 funding_frequency_ms: u64,
709 /// Period of time over which funding (the difference between book and
710 /// index prices) gets paid.
711 ///
712 /// Setting the funding period too long may cause the perpetual to start
713 /// trading at a very dislocated price to the index because there's less
714 /// of an incentive for basis arbitrageurs to push the prices back in
715 /// line since they would have to carry the basis risk for a longer
716 /// period of time.
717 ///
718 /// Setting the funding period too short may cause nobody to trade the
719 /// perpetual because there's too punitive of a price to pay in the case
720 /// the funding rate flips sign.
721 funding_period_ms: u64,
722 /// The time span between each funding TWAP (both index price and orderbook price) update.
723 premium_twap_frequency_ms: u64,
724 /// The reference time span used for weighting the TWAP (both index price and orderbook price)
725 /// updates for funding rates estimation
726 premium_twap_period_ms: u64,
727 /// The time span between each spread TWAP updates (used for liquidations).
728 spread_twap_frequency_ms: u64,
729 /// The reference time span used for weighting the TWAP updates for spread.
730 spread_twap_period_ms: u64,
731 /// Proportion of volume charged as fees from makers upon processing
732 /// fill events.
733 maker_fee: IFixed,
734 /// Proportion of volume charged as fees from takers after processing
735 /// fill events.
736 taker_fee: IFixed,
737 /// Proportion of volume charged as fees from liquidatees
738 liquidation_fee: IFixed,
739 /// Proportion of volume charged as fees from liquidatees after forced cancelling
740 /// of pending orders during liquidation.
741 force_cancel_fee: IFixed,
742 /// Proportion of volume charged as fees from liquidatees to deposit into insurance fund
743 insurance_fund_fee: IFixed,
744 /// Minimum USD value an order is required to be worth to be placed
745 min_order_usd_value: IFixed,
746 /// Number of base units exchanged per lot
747 lot_size: u64,
748 /// Number of quote units exchanged per tick
749 tick_size: u64,
750 /// Number of lots in a position that a liquidator may buy in excess of what would be
751 /// strictly required to bring the liqee's account back to IMR.
752 liquidation_tolerance: u64,
753 /// Maximum number of pending orders that a position can have.
754 max_pending_orders: u64,
755 /// Timestamp tolerance for base oracle price
756 base_oracle_tolerance: u64,
757 /// Timestamp tolerance for collateral oracle price
758 collateral_oracle_tolerance: u64,
759 /// Max open interest (in base tokens) available for this market
760 max_open_interest: IFixed,
761 /// The check on `max_open_interest_position_percent` is not performed if
762 /// the market's open interest is below this threshold.
763 max_open_interest_threshold: IFixed,
764 /// Max open interest percentage a position can have relative to total market's open interest
765 max_open_interest_position_percent: IFixed,
766 /// Scaling factor to use to convert collateral units to ifixed values and viceversa
767 scaling_factor: IFixed
768 }
769
770 /// The state of a perpetuals market.
771 struct MarketState has store {
772 /// The latest cumulative funding premium in this market for longs. Must be updated
773 /// periodically.
774 cum_funding_rate_long: IFixed,
775 /// The latest cumulative funding premium in this market for shorts. Must be updated
776 /// periodically.
777 cum_funding_rate_short: IFixed,
778 /// The timestamp (millisec) of the latest cumulative funding premium update
779 /// (both longs and shorts).
780 funding_last_upd_ms: u64,
781 /// The last calculated funding premium TWAP (used for funding settlement).
782 premium_twap: IFixed,
783 /// The timestamp (millisec) of the last update of `premium_twap`.
784 premium_twap_last_upd_ms: u64,
785 /// The last calculated spread TWAP (used for liquidations).
786 /// Spread is (book - index).
787 spread_twap: IFixed,
788 /// The timestamp (millisec) of `spread_twap` last update.
789 spread_twap_last_upd_ms: u64,
790 /// Open interest (in base tokens) as a fixed-point number. Counts the
791 /// total size of contracts as the sum of all long positions.
792 open_interest: IFixed,
793 /// Total amount of fees accrued by this market (in T's units)
794 /// Only admin can withdraw these fees.
795 fees_accrued: IFixed,
796 }
797 }
798
799 module orderbook {
800 /// An order on the orderbook
801 struct Order has copy, drop, store {
802 /// User's account id
803 account_id: u64,
804 /// Amount of lots to be filled
805 size: u64,
806 /// Optional reduce-only requirement for this order.
807 reduce_only: bool,
808 /// Optional expiration time for the order
809 expiration_timestamp_ms: Option<u64>
810 }
811
812 /// The orderbook doesn't know the types of tokens traded, it assumes a correct
813 /// management by the clearing house
814 struct Orderbook has key, store {
815 id: UID,
816 /// Number of limit orders placed on book, monotonically increases
817 counter: u64,
818 }
819 }
820
821 module ordered_map {
822 /// Ordered map with `u128` type as a key and `V` type as a value.
823 struct Map<!phantom V: copy + drop + store> has key, store {
824 /// Object UID for adding dynamic fields that are used as pointers to nodes.
825 id: UID,
826 /// Number of key-value pairs in the map.
827 size: u64,
828 /// Counter for creating another node as a dynamic field.
829 counter: u64,
830 /// Pointer to the root node, which is a branch or a leaf.
831 root: u64,
832 /// Pointer to first leaf.
833 first: u64,
834 /// Minimal number of kids in a non-root branch;
835 /// must satisfy 2 <= branch_min <= branch_max / 2.
836 branch_min: u64,
837 /// Maximal number of kids in a branch, which is merge of two branches;
838 /// must satisfy 2 * branch_min <= branches_merge_max <= branch_max.
839 branches_merge_max: u64,
840 /// Maximal number of kids in a branch.
841 branch_max: u64,
842 /// Minimal number of elements in a non-root leaf;
843 /// must satisfy 2 <= leaf_min <= (leaf_max + 1) / 2.
844 leaf_min: u64,
845 /// Maximal number of elements in a leaf, which is merge of two leaves;
846 /// must satisfy 2 * leaf_min - 1 <= leaves_merge_max <= leaf_max.
847 leaves_merge_max: u64,
848 /// Maximal number of elements in a leaf.
849 leaf_max: u64,
850 }
851
852 /// Branch node with kids and ordered separating keys.
853 struct Branch has drop, store {
854 /// Separating keys for kids sorted in ascending order.
855 keys: vector<u128>,
856 /// Kids of the node.
857 kids: vector<u64>,
858 }
859
860 /// Key-value pair.
861 struct Pair<V: copy + drop + store> has copy, drop, store {
862 key: u128,
863 val: V,
864 }
865
866 /// Leaf node with ordered key-value pairs.
867 struct Leaf<V: copy + drop + store> has drop, store {
868 /// Keys sorted in ascending order together with values.
869 keys_vals: vector<Pair<V>>,
870 /// Pointer to next leaf.
871 next: u64,
872 }
873 }
874
875 module position {
876 /// Stores information about an open position
877 struct Position has store {
878 /// Amount of allocated tokens (e.g., USD stables) backing this account's position.
879 collateral: IFixed,
880 /// The perpetual contract size, controlling the amount of exposure to
881 /// the underlying asset. Positive implies long position and negative,
882 /// short. Represented as a signed fixed-point number.
883 base_asset_amount: IFixed,
884 /// The entry value for this position, including leverage. Represented
885 /// as a signed fixed-point number.
886 quote_asset_notional_amount: IFixed,
887 /// Last long cumulative funding rate used to update this position. The
888 /// market's latest long cumulative funding rate minus this gives the funding
889 /// rate this position must pay. This rate multiplied by this position's
890 /// value (base asset amount * market price) gives the total funding
891 /// owed, which is deducted from the trader account's margin. This debt
892 /// is accounted for in margin ratio calculations, which may lead to
893 /// liquidation. Represented as a signed fixed-point number.
894 cum_funding_rate_long: IFixed,
895 /// Last short cumulative funding rate used to update this position. The
896 /// market's latest short cumulative funding rate minus this gives the funding
897 /// rate this position must pay. This rate multiplied by this position's
898 /// value (base asset amount * market price) gives the total funding
899 /// owed, which is deducted from the trader account's margin. This debt
900 /// is accounted for in margin ratio calculations, which may lead to
901 /// liquidation. Represented as a signed fixed-point number.
902 cum_funding_rate_short: IFixed,
903 /// Base asset amount resting in ask orders in the orderbook.
904 /// Represented as a signed fixed-point number.
905 asks_quantity: IFixed,
906 /// Base asset amount resting in bid orders in the orderbook.
907 /// Represented as a signed fixed-point number.
908 bids_quantity: IFixed,
909 /// Number of pending orders in this position.
910 pending_orders: u64,
911 /// Custom maker fee for this position, set at default value of 100%
912 maker_fee: IFixed,
913 /// Custom taker fee for this position, set at default value of 100%
914 taker_fee: IFixed,
915 /// Initial Margin Ratio set by user for the position. Must always be less
916 /// or equal than market's IMR. Used as a desired reference margin ratio when
917 /// managing collateral in the position during all the actions. Can be changed
918 /// by the user at any moment (between the allowed limits).
919 initial_margin_ratio: IFixed
920 }
921 }
922
923 module registry {
924 /// Registry object that maintains:
925 /// - A mapping between a clearing house id and `MarketInfo`
926 /// - A mapping between a collateral type `T` and `CollateralInfo`
927 /// It also maintains the global counter for account creation.
928 /// Minted and shared when the module is published.
929 struct Registry has key {
930 id: UID,
931 next_account_id: u64
932 }
933
934 /// Struct containing all the immutable info about a registered market
935 struct MarketInfo<!phantom T> has store {
936 base_pfs_id: ID,
937 collateral_pfs_id: ID,
938 lot_size: u64,
939 tick_size: u64,
940 scaling_factor: IFixed
941 }
942
943 /// Struct containing all the immutable info about the collateral
944 /// used in one or more markets
945 struct CollateralInfo<!phantom T> has store {
946 collateral_pfs_id: ID,
947 scaling_factor: IFixed
948 }
949
950 /// Config that stores useful info for the protocol
951 struct Config has store {
952 stop_order_mist_cost: u64,
953 }
954 }
955});
956
957impl<T: af_move_type::MoveType> clearing_house::ClearingHouse<T> {
958 /// Convenience function to build the type of a [`PositionDf`].
959 pub fn position_df_type(package: Address) -> FieldTypeTag<self::keys::Position, Position> {
960 Field::type_(
961 self::keys::Position::type_(package),
962 Position::type_(package),
963 )
964 }
965
966 /// Convenience function to build the type of an [`OrderbookDofWrapper`].
967 pub fn orderbook_dof_wrapper_type(
968 package: Address,
969 ) -> FieldTypeTag<Wrapper<keys::Orderbook>, ID> {
970 Field::type_(
971 Wrapper::type_(keys::Orderbook::type_(package)),
972 ID::type_(SUI_FRAMEWORK_ADDRESS, IdentStr::cast("object").to_owned()),
973 )
974 }
975
976 /// The ID of the package that governs this clearing house's logic.
977 ///
978 /// This may be different than the package defining the clearing house's type because a package
979 /// upgrade + `interface::upgrade_clearing_house_version` call can change
980 /// [`ClearingHouse::version`] so that the upgraded package is the one that is allowed to make
981 /// changes to it.
982 ///
983 /// Attempting to make a PTB Move call that mutates this clearing house but is not defined in
984 /// this package version will fail.
985 pub const fn governing_package_testnet(&self) -> ObjectId {
986 // NOTE: we published the most recent testnet contracts starting with `VERSION = 1`
987 TESTNET_PACKAGE_VERSIONS[self.version as usize - 1]
988 }
989}
990
991impl self::orderbook::Orderbook {
992 /// Convenience function to build the type of an [`AsksMapDofWrapper`].
993 pub fn asks_dof_wrapper_type(package: Address) -> FieldTypeTag<Wrapper<keys::AsksMap>, ID> {
994 Field::type_(
995 Wrapper::type_(keys::AsksMap::type_(package)),
996 ID::type_(SUI_FRAMEWORK_ADDRESS, IdentStr::cast("object").to_owned()),
997 )
998 }
999
1000 /// Convenience function to build the type of an [`BidsMapDofWrapper`].
1001 pub fn bids_dof_wrapper_type(package: Address) -> FieldTypeTag<Wrapper<keys::BidsMap>, ID> {
1002 Field::type_(
1003 Wrapper::type_(keys::BidsMap::type_(package)),
1004 ID::type_(SUI_FRAMEWORK_ADDRESS, IdentStr::cast("object").to_owned()),
1005 )
1006 }
1007}
1008
1009impl self::ordered_map::Map<Order> {
1010 /// Convenience function to build the type of an [`OrderLeafDf`].
1011 pub fn leaf_df_type(package: Address) -> FieldTypeTag<u64, self::ordered_map::Leaf<Order>> {
1012 Field::type_(
1013 af_move_type::U64TypeTag,
1014 self::ordered_map::Leaf::type_(package, Order::type_(package)),
1015 )
1016 }
1017}
1018
1019#[cfg(test)]
1020mod tests {
1021 /// Taken from
1022 /// <https://github.com/cargo-public-api/cargo-public-api?tab=readme-ov-file#-as-a-ci-check>
1023 #[test]
1024 fn public_api() {
1025 // Install a compatible nightly toolchain if it is missing
1026 rustup_toolchain::install(public_api::MINIMUM_NIGHTLY_RUST_VERSION).unwrap();
1027
1028 // Build rustdoc JSON
1029 let rustdoc_json = rustdoc_json::Builder::default()
1030 .toolchain(public_api::MINIMUM_NIGHTLY_RUST_VERSION)
1031 .build()
1032 .unwrap();
1033
1034 // Derive the public API from the rustdoc JSON
1035 let public_api = public_api::Builder::from_rustdoc_json(rustdoc_json)
1036 .omit_blanket_impls(true)
1037 .omit_auto_trait_impls(true)
1038 .omit_auto_derived_impls(true)
1039 .build()
1040 .unwrap();
1041
1042 // Assert that the public API looks correct
1043 insta::assert_snapshot!(public_api);
1044 }
1045}