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