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