use serde_derive::{Deserialize, Serialize};
use solana_sdk::pubkey::Pubkey;
use std::{error, fmt};
pub const SCALER: u64 = 1000;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum ExchangeError {
InvalidTrade(String),
}
impl error::Error for ExchangeError {}
impl fmt::Display for ExchangeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ExchangeError::InvalidTrade(s) => write!(f, "{}", s),
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum Token {
A,
B,
C,
D,
}
impl Default for Token {
fn default() -> Self {
Token::A
}
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[allow(non_snake_case)]
pub struct Tokens {
pub A: u64,
pub B: u64,
pub C: u64,
pub D: u64,
}
impl Tokens {
pub fn new(a: u64, b: u64, c: u64, d: u64) -> Self {
Self {
A: a,
B: b,
C: c,
D: d,
}
}
}
impl std::ops::Index<Token> for Tokens {
type Output = u64;
fn index(&self, t: Token) -> &u64 {
match t {
Token::A => &self.A,
Token::B => &self.B,
Token::C => &self.C,
Token::D => &self.D,
}
}
}
impl std::ops::IndexMut<Token> for Tokens {
fn index_mut(&mut self, t: Token) -> &mut u64 {
match t {
Token::A => &mut self.A,
Token::B => &mut self.B,
Token::C => &mut self.C,
Token::D => &mut self.D,
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[allow(non_snake_case)]
pub struct AssetPair {
pub Base: Token,
pub Quote: Token,
}
impl Default for AssetPair {
fn default() -> AssetPair {
AssetPair {
Base: Token::A,
Quote: Token::B,
}
}
}
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct TokenAccountInfo {
pub owner: Pubkey,
pub tokens: Tokens,
}
impl TokenAccountInfo {
pub fn owner(mut self, owner: &Pubkey) -> Self {
self.owner = *owner;
self
}
pub fn tokens(mut self, a: u64, b: u64, c: u64, d: u64) -> Self {
self.tokens = Tokens {
A: a,
B: b,
C: c,
D: d,
};
self
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum OrderSide {
Ask,
Bid,
}
impl fmt::Display for OrderSide {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OrderSide::Ask => write!(f, "A")?,
OrderSide::Bid => write!(f, "B")?,
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct OrderInfo {
pub owner: Pubkey,
pub side: OrderSide,
pub pair: AssetPair,
pub tokens: u64,
pub price: u64,
pub tokens_settled: u64,
}
impl Default for OrderInfo {
fn default() -> Self {
Self {
owner: Pubkey::default(),
pair: AssetPair::default(),
side: OrderSide::Ask,
tokens: 0,
price: 0,
tokens_settled: 0,
}
}
}
impl OrderInfo {
pub fn pair(mut self, pair: AssetPair) -> Self {
self.pair = pair;
self
}
pub fn side(mut self, side: OrderSide) -> Self {
self.side = side;
self
}
pub fn tokens(mut self, tokens: u64) -> Self {
self.tokens = tokens;
self
}
pub fn price(mut self, price: u64) -> Self {
self.price = price;
self
}
}
pub fn check_trade(side: OrderSide, tokens: u64, price: u64) -> Result<(), ExchangeError> {
match side {
OrderSide::Ask => {
if tokens * price / SCALER == 0 {
return Err(ExchangeError::InvalidTrade(format!(
"To trade of {} for {}/{} results in 0 tradeable tokens",
tokens, SCALER, price
)));
}
}
OrderSide::Bid => {
if tokens * SCALER / price == 0 {
return Err(ExchangeError::InvalidTrade(format!(
"From trade of {} for {}?{} results in 0 tradeable tokens",
tokens, SCALER, price
)));
}
}
}
Ok(())
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum ExchangeState {
Unallocated,
Account(TokenAccountInfo),
Trade(OrderInfo),
Invalid,
}
impl Default for ExchangeState {
fn default() -> Self {
ExchangeState::Unallocated
}
}