phoenix/program/
status.rs

1use super::{assert_with_msg, PhoenixError};
2use borsh::{BorshDeserialize, BorshSerialize};
3use solana_program::program_error::ProgramError;
4use std::fmt::Display;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
7#[repr(u64)]
8pub enum MarketStatus {
9    Uninitialized,
10    /// All new orders, placements, and reductions are accepted. Crossing the spread is permissionless.
11    Active,
12    /// Only places, reductions and withdrawals are accepted.
13    PostOnly,
14    /// Only reductions and withdrawals are accepted.
15    Paused,
16    /// Only reductions and withdrawals are accepted. The market authority can forcibly cancel
17    /// all orders.
18    Closed,
19    /// Used to signal the market to be deleted. Can only be called in a Closed state where all orders
20    /// and traders are removed from the book
21    Tombstoned,
22}
23
24impl Display for MarketStatus {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            MarketStatus::Uninitialized => write!(f, "Uninitialized"),
28            MarketStatus::Active => write!(f, "Active"),
29            MarketStatus::PostOnly => write!(f, "PostOnly"),
30            MarketStatus::Paused => write!(f, "Paused"),
31            MarketStatus::Closed => write!(f, "Closed"),
32            MarketStatus::Tombstoned => write!(f, "Tombstoned"),
33        }
34    }
35}
36
37impl Default for MarketStatus {
38    fn default() -> Self {
39        Self::Uninitialized
40    }
41}
42
43impl From<u64> for MarketStatus {
44    fn from(status: u64) -> Self {
45        match status {
46            0 => Self::Uninitialized,
47            1 => Self::Active,
48            2 => Self::PostOnly,
49            3 => Self::Paused,
50            4 => Self::Closed,
51            5 => Self::Tombstoned,
52            _ => panic!("Invalid market status"),
53        }
54    }
55}
56
57impl MarketStatus {
58    pub fn valid_state_transition(&self, new_state: &MarketStatus) -> bool {
59        matches!(
60            (self, new_state),
61            (MarketStatus::Uninitialized, MarketStatus::PostOnly)
62                | (MarketStatus::Active, MarketStatus::PostOnly)
63                | (MarketStatus::Active, MarketStatus::Paused)
64                | (MarketStatus::Active, MarketStatus::Active)
65                | (MarketStatus::PostOnly, MarketStatus::Active)
66                | (MarketStatus::PostOnly, MarketStatus::Paused)
67                | (MarketStatus::PostOnly, MarketStatus::Closed)
68                | (MarketStatus::PostOnly, MarketStatus::PostOnly)
69                | (MarketStatus::Closed, MarketStatus::Tombstoned)
70                | (MarketStatus::Closed, MarketStatus::Paused)
71                | (MarketStatus::Closed, MarketStatus::Closed)
72                | (MarketStatus::Closed, MarketStatus::PostOnly)
73                | (MarketStatus::Paused, MarketStatus::Active)
74                | (MarketStatus::Paused, MarketStatus::PostOnly)
75                | (MarketStatus::Paused, MarketStatus::Closed)
76                | (MarketStatus::Paused, MarketStatus::Paused)
77        )
78    }
79
80    pub fn assert_valid_state_transition(
81        &self,
82        new_state: &MarketStatus,
83    ) -> Result<(), ProgramError> {
84        assert_with_msg(
85            self.valid_state_transition(new_state),
86            PhoenixError::InvalidStateTransition,
87            "Invalid state transition",
88        )
89    }
90
91    pub fn cross_allowed(&self) -> bool {
92        matches!(self, MarketStatus::Active)
93    }
94
95    pub fn post_allowed(&self) -> bool {
96        matches!(self, MarketStatus::Active | MarketStatus::PostOnly)
97    }
98
99    pub fn reduce_allowed(&self) -> bool {
100        matches!(
101            self,
102            MarketStatus::Active
103                | MarketStatus::PostOnly
104                | MarketStatus::Paused
105                | MarketStatus::Closed
106        )
107    }
108
109    // TODO: Implement instructions for authority to withdraw funds in a Closed state
110    pub fn authority_can_cancel(&self) -> bool {
111        matches!(self, MarketStatus::Closed)
112    }
113}
114
115#[derive(Debug, Copy, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
116#[repr(u64)]
117pub enum SeatApprovalStatus {
118    NotApproved,
119    Approved,
120    Retired,
121}
122
123impl From<u64> for SeatApprovalStatus {
124    fn from(status: u64) -> Self {
125        match status {
126            0 => SeatApprovalStatus::NotApproved,
127            1 => SeatApprovalStatus::Approved,
128            2 => SeatApprovalStatus::Retired,
129            _ => panic!("Invalid approval status"),
130        }
131    }
132}
133
134impl Display for SeatApprovalStatus {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        match self {
137            SeatApprovalStatus::NotApproved => write!(f, "NotApproved"),
138            SeatApprovalStatus::Approved => write!(f, "Approved"),
139            SeatApprovalStatus::Retired => write!(f, "Retired"),
140        }
141    }
142}
143
144impl Default for SeatApprovalStatus {
145    fn default() -> Self {
146        SeatApprovalStatus::NotApproved
147    }
148}