1use {
2 serde_derive::{Deserialize, Serialize},
3 solana_sdk::pubkey::Pubkey,
4 std::{error, fmt},
5};
6
7pub const SCALER: u64 = 1000;
10
11#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
12pub enum ExchangeError {
13 InvalidTrade(String),
14}
15impl error::Error for ExchangeError {}
16impl fmt::Display for ExchangeError {
17 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18 match self {
19 ExchangeError::InvalidTrade(s) => write!(f, "{}", s),
20 }
21 }
22}
23
24#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
26pub enum Token {
27 A,
28 B,
29 C,
30 D,
31}
32impl Default for Token {
33 fn default() -> Self {
34 Token::A
35 }
36}
37
38#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
40#[allow(non_snake_case)]
41pub struct Tokens {
42 pub A: u64,
43 pub B: u64,
44 pub C: u64,
45 pub D: u64,
46}
47impl Tokens {
48 pub fn new(a: u64, b: u64, c: u64, d: u64) -> Self {
49 Self {
50 A: a,
51 B: b,
52 C: c,
53 D: d,
54 }
55 }
56}
57impl std::ops::Index<Token> for Tokens {
58 type Output = u64;
59 fn index(&self, t: Token) -> &u64 {
60 match t {
61 Token::A => &self.A,
62 Token::B => &self.B,
63 Token::C => &self.C,
64 Token::D => &self.D,
65 }
66 }
67}
68impl std::ops::IndexMut<Token> for Tokens {
69 fn index_mut(&mut self, t: Token) -> &mut u64 {
70 match t {
71 Token::A => &mut self.A,
72 Token::B => &mut self.B,
73 Token::C => &mut self.C,
74 Token::D => &mut self.D,
75 }
76 }
77}
78
79#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
80#[allow(non_snake_case)]
81pub struct AssetPair {
82 pub Base: Token,
84 pub Quote: Token,
86 }
88
89impl Default for AssetPair {
90 fn default() -> AssetPair {
91 AssetPair {
92 Base: Token::A,
93 Quote: Token::B,
94 }
95 }
96}
97
98#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
100pub struct TokenAccountInfo {
101 pub owner: Pubkey,
103 pub tokens: Tokens,
105}
106
107impl TokenAccountInfo {
108 pub fn owner(mut self, owner: &Pubkey) -> Self {
109 self.owner = *owner;
110 self
111 }
112 pub fn tokens(mut self, a: u64, b: u64, c: u64, d: u64) -> Self {
113 self.tokens = Tokens {
114 A: a,
115 B: b,
116 C: c,
117 D: d,
118 };
119 self
120 }
121}
122
123#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
125pub enum OrderSide {
126 Ask, Bid, }
131impl fmt::Display for OrderSide {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 match self {
134 OrderSide::Ask => write!(f, "A")?,
135 OrderSide::Bid => write!(f, "B")?,
136 }
137 Ok(())
138 }
139}
140
141#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
143pub struct OrderInfo {
144 pub owner: Pubkey,
146 pub side: OrderSide,
148 pub pair: AssetPair,
150 pub tokens: u64,
153 pub price: u64,
156 pub tokens_settled: u64,
159}
160impl Default for OrderInfo {
161 fn default() -> Self {
162 Self {
163 owner: Pubkey::default(),
164 pair: AssetPair::default(),
165 side: OrderSide::Ask,
166 tokens: 0,
167 price: 0,
168 tokens_settled: 0,
169 }
170 }
171}
172impl OrderInfo {
173 pub fn pair(mut self, pair: AssetPair) -> Self {
174 self.pair = pair;
175 self
176 }
177 pub fn side(mut self, side: OrderSide) -> Self {
178 self.side = side;
179 self
180 }
181 pub fn tokens(mut self, tokens: u64) -> Self {
182 self.tokens = tokens;
183 self
184 }
185 pub fn price(mut self, price: u64) -> Self {
186 self.price = price;
187 self
188 }
189}
190
191pub fn check_trade(side: OrderSide, tokens: u64, price: u64) -> Result<(), ExchangeError> {
192 match side {
193 OrderSide::Ask => {
194 if tokens * price / SCALER == 0 {
195 return Err(ExchangeError::InvalidTrade(format!(
196 "To trade of {} for {}/{} results in 0 tradeable tokens",
197 tokens, SCALER, price
198 )));
199 }
200 }
201 OrderSide::Bid => {
202 if tokens * SCALER / price == 0 {
203 return Err(ExchangeError::InvalidTrade(format!(
204 "From trade of {} for {}?{} results in 0 tradeable tokens",
205 tokens, SCALER, price
206 )));
207 }
208 }
209 }
210 Ok(())
211}
212
213#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
215pub enum ExchangeState {
216 Unallocated,
218 Account(TokenAccountInfo),
220 Trade(OrderInfo),
222 Invalid,
223}
224impl Default for ExchangeState {
225 fn default() -> Self {
226 ExchangeState::Unallocated
227 }
228}