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