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