1use std::collections::BTreeSet;
2
3use anchor_lang::prelude::{
4 borsh::{BorshDeserialize, BorshSerialize},
5 *,
6};
7
8pub const MAX_MARKET_CONFIG_FLAGS: usize = 128;
10
11pub const MAX_MARKET_CONFIG_FACTORS: usize = 128;
13
14pub const MAX_MARKET_FLAGS: usize = 8;
16
17pub const MAX_VIRTUAL_INVENTORY_FLAGS: usize = 8;
19
20#[derive(Debug, thiserror::Error)]
22pub enum MarketError {
23 #[error("not a collateral token")]
25 NotACollateralToken,
26 #[error("market config key out of range")]
28 ExceedMaxMarketConfigFactor,
29}
30
31type MarketResult<T> = std::result::Result<T, MarketError>;
32
33#[zero_copy]
35#[derive(BorshSerialize, BorshDeserialize)]
36#[cfg_attr(feature = "debug", derive(Debug))]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38pub struct MarketMeta {
39 pub market_token_mint: Pubkey,
41 pub index_token_mint: Pubkey,
43 pub long_token_mint: Pubkey,
45 pub short_token_mint: Pubkey,
47}
48
49impl MarketMeta {
50 #[inline]
52 pub fn is_collateral_token(&self, token: &Pubkey) -> bool {
53 *token == self.long_token_mint || *token == self.short_token_mint
54 }
55
56 pub fn pnl_token(&self, is_long: bool) -> Pubkey {
58 if is_long {
59 self.long_token_mint
60 } else {
61 self.short_token_mint
62 }
63 }
64
65 pub fn to_token_side(&self, token: &Pubkey) -> MarketResult<bool> {
67 if *token == self.long_token_mint {
68 Ok(true)
69 } else if *token == self.short_token_mint {
70 Ok(false)
71 } else {
72 Err(MarketError::NotACollateralToken)
73 }
74 }
75
76 pub fn opposite_token(&self, token: &Pubkey) -> MarketResult<&Pubkey> {
78 if *token == self.long_token_mint {
79 Ok(&self.short_token_mint)
80 } else if *token == self.short_token_mint {
81 Ok(&self.long_token_mint)
82 } else {
83 Err(MarketError::NotACollateralToken)
84 }
85 }
86
87 pub fn ordered_tokens(&self) -> BTreeSet<Pubkey> {
89 BTreeSet::from([
90 self.index_token_mint,
91 self.long_token_mint,
92 self.short_token_mint,
93 ])
94 }
95}
96
97pub trait HasMarketMeta {
99 fn market_meta(&self) -> &MarketMeta;
100
101 fn is_pure(&self) -> bool {
102 let meta = self.market_meta();
103 meta.long_token_mint == meta.short_token_mint
104 }
105}
106
107impl HasMarketMeta for MarketMeta {
108 fn market_meta(&self) -> &MarketMeta {
109 self
110 }
111}
112
113pub fn ordered_tokens(from: &impl HasMarketMeta, to: &impl HasMarketMeta) -> BTreeSet<Pubkey> {
115 let mut tokens = BTreeSet::default();
116
117 let from = from.market_meta();
118 let to = to.market_meta();
119
120 for mint in [
121 &from.index_token_mint,
122 &from.long_token_mint,
123 &from.short_token_mint,
124 ]
125 .iter()
126 .chain(&[
127 &to.index_token_mint,
128 &to.long_token_mint,
129 &to.short_token_mint,
130 ]) {
131 tokens.insert(**mint);
132 }
133 tokens
134}
135
136#[derive(
138 strum::EnumString,
139 strum::Display,
140 Clone,
141 Copy,
142 PartialEq,
143 Eq,
144 PartialOrd,
145 Ord,
146 Hash,
147 num_enum::TryFromPrimitive,
148 num_enum::IntoPrimitive,
149)]
150#[strum(serialize_all = "snake_case")]
151#[cfg_attr(feature = "debug", derive(Debug))]
152#[cfg_attr(feature = "enum-iter", derive(strum::EnumIter))]
153#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
154#[cfg_attr(feature = "clap", clap(rename_all = "snake_case"))]
155#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
156#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
157#[non_exhaustive]
158#[repr(u8)]
159pub enum MarketConfigFlag {
160 SkipBorrowingFeeForSmallerSide,
162 IgnoreOpenInterestForUsageFactor,
164 EnableMarketClosedParams,
166 MarketClosedSkipBorrowingFeeForSmallerSide,
168 }
170
171#[derive(
173 strum::EnumString,
174 strum::Display,
175 Clone,
176 Copy,
177 PartialEq,
178 Eq,
179 PartialOrd,
180 Ord,
181 Hash,
182 num_enum::TryFromPrimitive,
183 num_enum::IntoPrimitive,
184)]
185#[strum(serialize_all = "snake_case")]
186#[cfg_attr(feature = "debug", derive(Debug))]
187#[cfg_attr(feature = "enum-iter", derive(strum::EnumIter))]
188#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
189#[cfg_attr(feature = "clap", clap(rename_all = "snake_case"))]
190#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
191#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
192#[non_exhaustive]
193#[repr(u16)]
194pub enum MarketConfigKey {
195 SwapImpactExponent,
197 SwapImpactPositiveFactor,
199 SwapImpactNegativeFactor,
201 SwapFeeReceiverFactor,
203 SwapFeeFactorForPositiveImpact,
205 SwapFeeFactorForNegativeImpact,
207 MinPositionSizeUsd,
209 MinCollateralValue,
211 MinCollateralFactor,
213 MinCollateralFactorForOpenInterestMultiplierForLong,
215 MinCollateralFactorForOpenInterestMultiplierForShort,
217 MaxPositivePositionImpactFactor,
219 MaxNegativePositionImpactFactor,
221 MaxPositionImpactFactorForLiquidations,
223 PositionImpactExponent,
225 PositionImpactPositiveFactor,
227 PositionImpactNegativeFactor,
229 OrderFeeReceiverFactor,
231 OrderFeeFactorForPositiveImpact,
233 OrderFeeFactorForNegativeImpact,
235 LiquidationFeeReceiverFactor,
237 LiquidationFeeFactor,
239 PositionImpactDistributeFactor,
241 MinPositionImpactPoolAmount,
243 BorrowingFeeReceiverFactor,
245 BorrowingFeeFactorForLong,
247 BorrowingFeeFactorForShort,
249 BorrowingFeeExponentForLong,
251 BorrowingFeeExponentForShort,
253 BorrowingFeeOptimalUsageFactorForLong,
255 BorrowingFeeOptimalUsageFactorForShort,
257 BorrowingFeeBaseFactorForLong,
259 BorrowingFeeBaseFactorForShort,
261 BorrowingFeeAboveOptimalUsageFactorForLong,
263 BorrowingFeeAboveOptimalUsageFactorForShort,
265 FundingFeeExponent,
267 FundingFeeFactor,
269 FundingFeeMaxFactorPerSecond,
271 FundingFeeMinFactorPerSecond,
273 FundingFeeIncreaseFactorPerSecond,
275 FundingFeeDecreaseFactorPerSecond,
277 FundingFeeThresholdForStableFunding,
279 FundingFeeThresholdForDecreaseFunding,
281 ReserveFactor,
283 OpenInterestReserveFactor,
285 MaxPnlFactorForLongDeposit,
287 MaxPnlFactorForShortDeposit,
289 MaxPnlFactorForLongWithdrawal,
291 MaxPnlFactorForShortWithdrawal,
293 MaxPnlFactorForLongTrader,
295 MaxPnlFactorForShortTrader,
297 MaxPnlFactorForLongAdl,
299 MaxPnlFactorForShortAdl,
301 MinPnlFactorAfterLongAdl,
303 MinPnlFactorAfterShortAdl,
305 MaxPoolAmountForLongToken,
307 MaxPoolAmountForShortToken,
309 MaxPoolValueForDepositForLongToken,
311 MaxPoolValueForDepositForShortToken,
313 MaxOpenInterestForLong,
315 MaxOpenInterestForShort,
317 MinTokensForFirstDeposit,
319 MinCollateralFactorForLiquidation,
321 MarketClosedMinCollateralFactorForLiquidation,
323 MarketClosedBorrowingFeeBaseFactor,
325 MarketClosedBorrowingFeeAboveOptimalUsageFactor,
327}
328
329#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
331#[cfg_attr(feature = "debug", derive(Debug))]
332#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
333#[cfg_attr(feature = "serde", serde(try_from = "MarketConfigKey"))]
334pub struct MarketConfigFactor(MarketConfigKey);
335
336impl From<MarketConfigFactor> for u8 {
337 fn from(value: MarketConfigFactor) -> Self {
338 u16::from(value.0).try_into().expect("must success")
339 }
340}
341
342impl TryFrom<MarketConfigKey> for MarketConfigFactor {
343 type Error = MarketError;
344
345 fn try_from(value: MarketConfigKey) -> std::result::Result<Self, Self::Error> {
346 let index = usize::from(u16::from(value));
347 if index > MAX_MARKET_CONFIG_FACTORS - 1 {
348 Err(MarketError::ExceedMaxMarketConfigFactor)
349 } else {
350 Ok(Self(value))
351 }
352 }
353}
354
355#[cfg(feature = "display")]
356impl std::fmt::Display for MarketConfigFactor {
357 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358 write!(f, "{}", &self.0)
359 }
360}
361
362#[derive(num_enum::IntoPrimitive)]
364#[repr(u8)]
365#[non_exhaustive]
366pub enum MarketFlag {
367 Enabled,
369 Pure,
371 AutoDeleveragingEnabledForLong,
373 AutoDeleveragingEnabledForShort,
375 GTEnabled,
377 Closed,
379 }
381
382#[derive(num_enum::IntoPrimitive)]
384#[repr(u8)]
385pub enum VirtualInventoryFlag {
386 Disabled,
388 }