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