gmsol_utils/
market.rs

1use std::collections::BTreeSet;
2
3use anchor_lang::prelude::{
4    borsh::{BorshDeserialize, BorshSerialize},
5    *,
6};
7
8/// Max number of config flags.
9pub const MAX_MARKET_CONFIG_FLAGS: usize = 128;
10
11/// Market error.
12#[derive(Debug, thiserror::Error)]
13pub enum MarketError {
14    /// Not a collateral token.
15    #[error("not a collateral token")]
16    NotACollateralToken,
17}
18
19type MarketResult<T> = std::result::Result<T, MarketError>;
20
21/// Market Metadata.
22#[zero_copy]
23#[derive(BorshSerialize, BorshDeserialize)]
24#[cfg_attr(feature = "debug", derive(Debug))]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct MarketMeta {
27    /// Market token.
28    pub market_token_mint: Pubkey,
29    /// Index token.
30    pub index_token_mint: Pubkey,
31    /// Long token.
32    pub long_token_mint: Pubkey,
33    /// Short token.
34    pub short_token_mint: Pubkey,
35}
36
37impl MarketMeta {
38    /// Check if the given token is a valid collateral token.
39    #[inline]
40    pub fn is_collateral_token(&self, token: &Pubkey) -> bool {
41        *token == self.long_token_mint || *token == self.short_token_mint
42    }
43
44    /// Get pnl token.
45    pub fn pnl_token(&self, is_long: bool) -> Pubkey {
46        if is_long {
47            self.long_token_mint
48        } else {
49            self.short_token_mint
50        }
51    }
52
53    /// Check if the given token is long token or short token, and return it's side.
54    pub fn to_token_side(&self, token: &Pubkey) -> MarketResult<bool> {
55        if *token == self.long_token_mint {
56            Ok(true)
57        } else if *token == self.short_token_mint {
58            Ok(false)
59        } else {
60            Err(MarketError::NotACollateralToken)
61        }
62    }
63
64    /// Get opposite token.
65    pub fn opposite_token(&self, token: &Pubkey) -> MarketResult<&Pubkey> {
66        if *token == self.long_token_mint {
67            Ok(&self.short_token_mint)
68        } else if *token == self.short_token_mint {
69            Ok(&self.long_token_mint)
70        } else {
71            Err(MarketError::NotACollateralToken)
72        }
73    }
74
75    /// Get ordered token set.
76    pub fn ordered_tokens(&self) -> BTreeSet<Pubkey> {
77        BTreeSet::from([
78            self.index_token_mint,
79            self.long_token_mint,
80            self.short_token_mint,
81        ])
82    }
83}
84
85/// Type that has market meta.
86pub trait HasMarketMeta {
87    fn market_meta(&self) -> &MarketMeta;
88
89    fn is_pure(&self) -> bool {
90        let meta = self.market_meta();
91        meta.long_token_mint == meta.short_token_mint
92    }
93}
94
95impl HasMarketMeta for MarketMeta {
96    fn market_meta(&self) -> &MarketMeta {
97        self
98    }
99}
100
101/// Get related tokens from markets in order.
102pub fn ordered_tokens(from: &impl HasMarketMeta, to: &impl HasMarketMeta) -> BTreeSet<Pubkey> {
103    let mut tokens = BTreeSet::default();
104
105    let from = from.market_meta();
106    let to = to.market_meta();
107
108    for mint in [
109        &from.index_token_mint,
110        &from.long_token_mint,
111        &from.short_token_mint,
112    ]
113    .iter()
114    .chain(&[
115        &to.index_token_mint,
116        &to.long_token_mint,
117        &to.short_token_mint,
118    ]) {
119        tokens.insert(**mint);
120    }
121    tokens
122}
123
124/// Market Config Flags.
125#[derive(
126    strum::EnumString,
127    strum::Display,
128    Clone,
129    Copy,
130    PartialEq,
131    Eq,
132    PartialOrd,
133    Ord,
134    Hash,
135    num_enum::TryFromPrimitive,
136    num_enum::IntoPrimitive,
137)]
138#[strum(serialize_all = "snake_case")]
139#[cfg_attr(feature = "debug", derive(Debug))]
140#[cfg_attr(feature = "enum-iter", derive(strum::EnumIter))]
141#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
142#[cfg_attr(feature = "clap", clap(rename_all = "snake_case"))]
143#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
144#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
145#[non_exhaustive]
146#[repr(u8)]
147pub enum MarketConfigFlag {
148    /// Skip borrowing fee for smaller side.
149    SkipBorrowingFeeForSmallerSide,
150    /// Ignore open interest for usage factor.
151    IgnoreOpenInterestForUsageFactor,
152    // CHECK: cannot have more than `MAX_CONFIG_FLAGS` flags.
153}
154
155/// Market config keys.
156#[derive(
157    strum::EnumString,
158    strum::Display,
159    Clone,
160    Copy,
161    PartialEq,
162    Eq,
163    PartialOrd,
164    Ord,
165    Hash,
166    num_enum::TryFromPrimitive,
167    num_enum::IntoPrimitive,
168)]
169#[strum(serialize_all = "snake_case")]
170#[cfg_attr(feature = "debug", derive(Debug))]
171#[cfg_attr(feature = "enum-iter", derive(strum::EnumIter))]
172#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
173#[cfg_attr(feature = "clap", clap(rename_all = "snake_case"))]
174#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
175#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
176#[non_exhaustive]
177#[repr(u16)]
178pub enum MarketConfigKey {
179    /// Swap impact exponent.
180    SwapImpactExponent,
181    /// Swap impact positive factor.
182    SwapImpactPositiveFactor,
183    /// Swap impact negative factor.
184    SwapImpactNegativeFactor,
185    /// Swap fee receiver factor.
186    SwapFeeReceiverFactor,
187    /// Swap fee factor for positive impact.
188    SwapFeeFactorForPositiveImpact,
189    /// Swap fee factor for negative impact.
190    SwapFeeFactorForNegativeImpact,
191    /// Min position size usd.
192    MinPositionSizeUsd,
193    /// Min collateral value.
194    MinCollateralValue,
195    /// Min collateral factor.
196    MinCollateralFactor,
197    /// Min collateral factor for open interest multiplier for long.
198    MinCollateralFactorForOpenInterestMultiplierForLong,
199    /// Min collateral factor for open interest multiplier for short.
200    MinCollateralFactorForOpenInterestMultiplierForShort,
201    /// Max positive position impact factor.
202    MaxPositivePositionImpactFactor,
203    /// Max negative position impact factor.
204    MaxNegativePositionImpactFactor,
205    /// Max position impact factor for liquidations.
206    MaxPositionImpactFactorForLiquidations,
207    /// Position impact exponent.
208    PositionImpactExponent,
209    /// Position impact positive factor.
210    PositionImpactPositiveFactor,
211    /// Position impact negative factor.
212    PositionImpactNegativeFactor,
213    /// Order fee receiver factor.
214    OrderFeeReceiverFactor,
215    /// Order fee factor for positive impact.
216    OrderFeeFactorForPositiveImpact,
217    /// Order fee factor for negative impact.
218    OrderFeeFactorForNegativeImpact,
219    /// Liquidation fee receiver factor.
220    LiquidationFeeReceiverFactor,
221    /// Liquidation fee factor.
222    LiquidationFeeFactor,
223    /// Position impact distribute factor.
224    PositionImpactDistributeFactor,
225    /// Min position impact pool amount.
226    MinPositionImpactPoolAmount,
227    /// Borrowing fee receiver factor.
228    BorrowingFeeReceiverFactor,
229    /// Borrowing fee factor for long.
230    BorrowingFeeFactorForLong,
231    /// Borrowing fee factor for short.
232    BorrowingFeeFactorForShort,
233    /// Borrowing fee exponent for long.
234    BorrowingFeeExponentForLong,
235    /// Borrowing fee exponent for short.
236    BorrowingFeeExponentForShort,
237    /// Borrowing fee optimal usage factor for long.
238    BorrowingFeeOptimalUsageFactorForLong,
239    /// Borrowing fee optimal usage factor for short.
240    BorrowingFeeOptimalUsageFactorForShort,
241    /// Borrowing fee base factor for long.
242    BorrowingFeeBaseFactorForLong,
243    /// Borrowing fee base factor for short.
244    BorrowingFeeBaseFactorForShort,
245    /// Borrowing fee above optimal usage factor for long.
246    BorrowingFeeAboveOptimalUsageFactorForLong,
247    /// Borrowing fee above optimal usage factor for short.
248    BorrowingFeeAboveOptimalUsageFactorForShort,
249    /// Funding fee exponent.
250    FundingFeeExponent,
251    /// Funding fee factor.
252    FundingFeeFactor,
253    /// Funding fee max factor per second.
254    FundingFeeMaxFactorPerSecond,
255    /// Funding fee min factor per second.
256    FundingFeeMinFactorPerSecond,
257    /// Funding fee increase factor per second.
258    FundingFeeIncreaseFactorPerSecond,
259    /// Funding fee decrease factor per second.
260    FundingFeeDecreaseFactorPerSecond,
261    /// Funding fee threshold for stable funding.
262    FundingFeeThresholdForStableFunding,
263    /// Funding fee threshold for decrease funding.
264    FundingFeeThresholdForDecreaseFunding,
265    /// Reserve factor.
266    ReserveFactor,
267    /// Open interest reserve factor.
268    OpenInterestReserveFactor,
269    /// Max PNL factor for long deposit.
270    MaxPnlFactorForLongDeposit,
271    /// Max PNL factor for short deposit.
272    MaxPnlFactorForShortDeposit,
273    /// Max PNL factor for long withdrawal.
274    MaxPnlFactorForLongWithdrawal,
275    /// Max PNL factor for short withdrawal.
276    MaxPnlFactorForShortWithdrawal,
277    /// Max PNL factor for long trader.
278    MaxPnlFactorForLongTrader,
279    /// Max PNL factor for short trader.
280    MaxPnlFactorForShortTrader,
281    /// Max PNL factor for long ADL.
282    MaxPnlFactorForLongAdl,
283    /// Max PNL factor for short ADL.
284    MaxPnlFactorForShortAdl,
285    /// Min PNL factor after long ADL.
286    MinPnlFactorAfterLongAdl,
287    /// Min PNL factor after short ADL.
288    MinPnlFactorAfterShortAdl,
289    /// Max pool amount for long token.
290    MaxPoolAmountForLongToken,
291    /// Max pool amount for short token.
292    MaxPoolAmountForShortToken,
293    /// Max pool value for deposit for long token.
294    MaxPoolValueForDepositForLongToken,
295    /// Max pool value for deposit for short token.
296    MaxPoolValueForDepositForShortToken,
297    /// Max open interest for long.
298    MaxOpenInterestForLong,
299    /// Max open interest for short.
300    MaxOpenInterestForShort,
301    /// Min tokens for first deposit.
302    MinTokensForFirstDeposit,
303}