use std::collections::BTreeSet;
use anchor_lang::prelude::{
borsh::{BorshDeserialize, BorshSerialize},
*,
};
pub const MAX_MARKET_CONFIG_FLAGS: usize = 128;
pub const MAX_MARKET_CONFIG_FACTORS: usize = 128;
pub const MAX_MARKET_FLAGS: usize = 8;
pub const MAX_VIRTUAL_INVENTORY_FLAGS: usize = 8;
#[derive(Debug, thiserror::Error)]
pub enum MarketError {
#[error("not a collateral token")]
NotACollateralToken,
#[error("market config key out of range")]
ExceedMaxMarketConfigFactor,
}
type MarketResult<T> = std::result::Result<T, MarketError>;
#[zero_copy]
#[derive(BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MarketMeta {
pub market_token_mint: Pubkey,
pub index_token_mint: Pubkey,
pub long_token_mint: Pubkey,
pub short_token_mint: Pubkey,
}
impl MarketMeta {
#[inline]
pub fn is_collateral_token(&self, token: &Pubkey) -> bool {
*token == self.long_token_mint || *token == self.short_token_mint
}
pub fn pnl_token(&self, is_long: bool) -> Pubkey {
if is_long {
self.long_token_mint
} else {
self.short_token_mint
}
}
pub fn to_token_side(&self, token: &Pubkey) -> MarketResult<bool> {
if *token == self.long_token_mint {
Ok(true)
} else if *token == self.short_token_mint {
Ok(false)
} else {
Err(MarketError::NotACollateralToken)
}
}
pub fn opposite_token(&self, token: &Pubkey) -> MarketResult<&Pubkey> {
if *token == self.long_token_mint {
Ok(&self.short_token_mint)
} else if *token == self.short_token_mint {
Ok(&self.long_token_mint)
} else {
Err(MarketError::NotACollateralToken)
}
}
pub fn ordered_tokens(&self) -> BTreeSet<Pubkey> {
BTreeSet::from([
self.index_token_mint,
self.long_token_mint,
self.short_token_mint,
])
}
}
pub trait HasMarketMeta {
fn market_meta(&self) -> &MarketMeta;
fn is_pure(&self) -> bool {
let meta = self.market_meta();
meta.long_token_mint == meta.short_token_mint
}
}
impl HasMarketMeta for MarketMeta {
fn market_meta(&self) -> &MarketMeta {
self
}
}
pub fn ordered_tokens(from: &impl HasMarketMeta, to: &impl HasMarketMeta) -> BTreeSet<Pubkey> {
let mut tokens = BTreeSet::default();
let from = from.market_meta();
let to = to.market_meta();
for mint in [
&from.index_token_mint,
&from.long_token_mint,
&from.short_token_mint,
]
.iter()
.chain(&[
&to.index_token_mint,
&to.long_token_mint,
&to.short_token_mint,
]) {
tokens.insert(**mint);
}
tokens
}
#[derive(
strum::EnumString,
strum::Display,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
num_enum::TryFromPrimitive,
num_enum::IntoPrimitive,
)]
#[strum(serialize_all = "snake_case")]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "enum-iter", derive(strum::EnumIter))]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "clap", clap(rename_all = "snake_case"))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[non_exhaustive]
#[repr(u8)]
pub enum MarketConfigFlag {
SkipBorrowingFeeForSmallerSide,
IgnoreOpenInterestForUsageFactor,
EnableMarketClosedParams,
MarketClosedSkipBorrowingFeeForSmallerSide,
}
#[derive(
strum::EnumString,
strum::Display,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
num_enum::TryFromPrimitive,
num_enum::IntoPrimitive,
)]
#[strum(serialize_all = "snake_case")]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "enum-iter", derive(strum::EnumIter))]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "clap", clap(rename_all = "snake_case"))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[non_exhaustive]
#[repr(u16)]
pub enum MarketConfigKey {
SwapImpactExponent,
SwapImpactPositiveFactor,
SwapImpactNegativeFactor,
SwapFeeReceiverFactor,
SwapFeeFactorForPositiveImpact,
SwapFeeFactorForNegativeImpact,
MinPositionSizeUsd,
MinCollateralValue,
MinCollateralFactor,
MinCollateralFactorForOpenInterestMultiplierForLong,
MinCollateralFactorForOpenInterestMultiplierForShort,
MaxPositivePositionImpactFactor,
MaxNegativePositionImpactFactor,
MaxPositionImpactFactorForLiquidations,
PositionImpactExponent,
PositionImpactPositiveFactor,
PositionImpactNegativeFactor,
OrderFeeReceiverFactor,
OrderFeeFactorForPositiveImpact,
OrderFeeFactorForNegativeImpact,
LiquidationFeeReceiverFactor,
LiquidationFeeFactor,
PositionImpactDistributeFactor,
MinPositionImpactPoolAmount,
BorrowingFeeReceiverFactor,
BorrowingFeeFactorForLong,
BorrowingFeeFactorForShort,
BorrowingFeeExponentForLong,
BorrowingFeeExponentForShort,
BorrowingFeeOptimalUsageFactorForLong,
BorrowingFeeOptimalUsageFactorForShort,
BorrowingFeeBaseFactorForLong,
BorrowingFeeBaseFactorForShort,
BorrowingFeeAboveOptimalUsageFactorForLong,
BorrowingFeeAboveOptimalUsageFactorForShort,
FundingFeeExponent,
FundingFeeFactor,
FundingFeeMaxFactorPerSecond,
FundingFeeMinFactorPerSecond,
FundingFeeIncreaseFactorPerSecond,
FundingFeeDecreaseFactorPerSecond,
FundingFeeThresholdForStableFunding,
FundingFeeThresholdForDecreaseFunding,
ReserveFactor,
OpenInterestReserveFactor,
MaxPnlFactorForLongDeposit,
MaxPnlFactorForShortDeposit,
MaxPnlFactorForLongWithdrawal,
MaxPnlFactorForShortWithdrawal,
MaxPnlFactorForLongTrader,
MaxPnlFactorForShortTrader,
MaxPnlFactorForLongAdl,
MaxPnlFactorForShortAdl,
MinPnlFactorAfterLongAdl,
MinPnlFactorAfterShortAdl,
MaxPoolAmountForLongToken,
MaxPoolAmountForShortToken,
MaxPoolValueForDepositForLongToken,
MaxPoolValueForDepositForShortToken,
MaxOpenInterestForLong,
MaxOpenInterestForShort,
MinTokensForFirstDeposit,
MinCollateralFactorForLiquidation,
MarketClosedMinCollateralFactorForLiquidation,
MarketClosedBorrowingFeeBaseFactor,
MarketClosedBorrowingFeeAboveOptimalUsageFactor,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "MarketConfigKey"))]
pub struct MarketConfigFactor(MarketConfigKey);
impl From<MarketConfigFactor> for u8 {
fn from(value: MarketConfigFactor) -> Self {
u16::from(value.0).try_into().expect("must success")
}
}
impl TryFrom<MarketConfigKey> for MarketConfigFactor {
type Error = MarketError;
fn try_from(value: MarketConfigKey) -> std::result::Result<Self, Self::Error> {
let index = usize::from(u16::from(value));
if index > MAX_MARKET_CONFIG_FACTORS - 1 {
Err(MarketError::ExceedMaxMarketConfigFactor)
} else {
Ok(Self(value))
}
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for MarketConfigFactor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.0)
}
}
#[derive(num_enum::IntoPrimitive)]
#[repr(u8)]
#[non_exhaustive]
pub enum MarketFlag {
Enabled,
Pure,
AutoDeleveragingEnabledForLong,
AutoDeleveragingEnabledForShort,
GTEnabled,
Closed,
}
#[derive(num_enum::IntoPrimitive)]
#[repr(u8)]
pub enum VirtualInventoryFlag {
Disabled,
}