vortex_common/
types.rs

1use std::fmt;
2use std::io::Write;
3
4use crate::utils::SignedDecimal;
5use cosmwasm_std::{Decimal, StdError};
6use cw_storage_plus::{Key, KeyDeserialize, Prefixer, PrimaryKey};
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
11pub struct Order {
12    pub id: u64,
13    pub account: String,
14    pub price_denom: String,
15    pub asset_denom: String,
16    pub price: SignedDecimal,
17    pub quantity: SignedDecimal,
18    pub remaining_quantity: SignedDecimal,
19    pub direction: PositionDirection,
20    pub effect: PositionEffect,
21    pub leverage: SignedDecimal,
22    pub order_type: OrderType,
23}
24
25#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
26pub struct FundingPaymentRate {
27    pub price_diff: SignedDecimal,
28    pub epoch: i64,
29}
30
31#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, JsonSchema, Eq, Hash)]
32pub enum PositionDirection {
33    Unknown,
34    Long,
35    Short,
36}
37
38impl fmt::Display for PositionDirection {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            PositionDirection::Unknown => write!(f, "Unknown"),
42            PositionDirection::Long => write!(f, "Long"),
43            PositionDirection::Short => write!(f, "Short"),
44        }
45    }
46}
47
48#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, JsonSchema, Eq, Hash)]
49pub enum PositionEffect {
50    Unknown,
51    Open,
52    Close,
53}
54
55impl fmt::Display for PositionEffect {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        match self {
58            PositionEffect::Unknown => write!(f, "Unknown"),
59            PositionEffect::Open => write!(f, "Open"),
60            PositionEffect::Close => write!(f, "Close"),
61        }
62    }
63}
64
65#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, JsonSchema, Eq, Hash)]
66pub enum OrderType {
67    Unknown,
68    Limit,
69    Market,
70    Liquidation,
71    Fokmarket,
72    Fokmarketbyvalue,
73}
74
75impl fmt::Display for OrderType {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        match self {
78            OrderType::Unknown => write!(f, "Unknown"),
79            OrderType::Limit => write!(f, "Limit"),
80            OrderType::Market => write!(f, "Market"),
81            OrderType::Liquidation => write!(f, "Liquidation"),
82            OrderType::Fokmarket => write!(f, "Fokmarket"),
83            OrderType::Fokmarketbyvalue => write!(f, "Fokmarketbyvalue"),
84        }
85    }
86}
87
88pub fn i32_to_order_type(i: i32) -> OrderType {
89    match i {
90        0i32 => OrderType::Limit,
91        1i32 => OrderType::Market,
92        2i32 => OrderType::Liquidation,
93        3i32 => OrderType::Fokmarket,
94        4i32 => OrderType::Fokmarketbyvalue,
95        _ => OrderType::Unknown,
96    }
97}
98
99pub fn order_type_to_i32(o: OrderType) -> i32 {
100    match o {
101        OrderType::Limit => 0i32,
102        OrderType::Market => 1i32,
103        OrderType::Liquidation => 2i32,
104        OrderType::Fokmarket => 3i32,
105        OrderType::Fokmarketbyvalue => 4i32,
106        OrderType::Unknown => -1i32,
107    }
108}
109
110pub fn i32_to_direction(i: i32) -> PositionDirection {
111    match i {
112        0i32 => PositionDirection::Long,
113        1i32 => PositionDirection::Short,
114        _ => PositionDirection::Unknown,
115    }
116}
117
118pub fn direction_to_i32(d: PositionDirection) -> i32 {
119    match d {
120        PositionDirection::Long => 0i32,
121        PositionDirection::Short => 1i32,
122        PositionDirection::Unknown => -1i32,
123    }
124}
125
126#[derive(Clone, Serialize, Deserialize, Hash, PartialEq, Eq, Debug, JsonSchema)]
127// price denom, asset denom
128// use string because we want to be able to dynamically add new token support
129pub struct Pair {
130    pub price_denom: String,
131    pub asset_denom: String,
132}
133
134impl Pair {
135    fn to_bytes(&self) -> [u8; 16] {
136        let mut price_denom_bytes: [u8; 8] = [0; 8];
137        let mut asset_denom_bytes: [u8; 8] = [0; 8];
138        let mut bytes = [0 as u8; 16];
139
140        self.fill_bytes_from_price_denom(&mut price_denom_bytes);
141        self.fill_bytes_from_asset_denom(&mut asset_denom_bytes);
142
143        for i in 0..8 {
144            bytes[i] = price_denom_bytes[i];
145            bytes[i + 8] = asset_denom_bytes[i];
146        }
147
148        bytes
149    }
150
151    pub fn fill_bytes_from_price_denom(&self, mut bytes: &mut [u8]) {
152        bytes.write(self.price_denom.as_bytes()).unwrap();
153    }
154
155    pub fn fill_bytes_from_asset_denom(&self, mut bytes: &mut [u8]) {
156        bytes.write(self.asset_denom.as_bytes()).unwrap();
157    }
158}
159
160// enable Pair to be returned from `range_de()` and friends.
161impl KeyDeserialize for Pair {
162    type Output = Pair;
163
164    fn from_vec(value: Vec<u8>) -> cosmwasm_std::StdResult<Self::Output> {
165        if value.len() != 16 {
166            return Err(StdError::ParseErr {
167                target_type: "pair".to_owned(),
168                msg: "bytes should have a length of 16".to_owned(),
169            });
170        }
171        let mut price_denom_last_char_idx = 8;
172        while price_denom_last_char_idx > 0 && value[price_denom_last_char_idx - 1] == 0 {
173            price_denom_last_char_idx -= 1;
174        }
175        let price_value = value.get(0..price_denom_last_char_idx).unwrap();
176        let price_denom = std::str::from_utf8(price_value).unwrap().to_string();
177        let mut asset_denom_last_char_idx = 16;
178        while asset_denom_last_char_idx > 8 && value[asset_denom_last_char_idx - 1] == 0 {
179            asset_denom_last_char_idx -= 1;
180        }
181        let asset_value = value.get(8..asset_denom_last_char_idx).unwrap();
182        let asset_denom = std::str::from_utf8(asset_value).unwrap().to_string();
183
184        Ok(Pair {
185            price_denom: price_denom,
186            asset_denom: asset_denom,
187        })
188    }
189}
190
191impl<'a> Prefixer<'a> for Pair {
192    fn prefix(&self) -> Vec<Key> {
193        vec![Key::Val128(self.to_bytes())]
194    }
195}
196
197// allow Pair as part of key of cw_storage_plus::Map
198impl<'a> PrimaryKey<'a> for Pair {
199    type Prefix = ();
200
201    type SubPrefix = ();
202
203    type Suffix = Self;
204
205    type SuperSuffix = Self;
206
207    fn key(&self) -> Vec<cw_storage_plus::Key> {
208        vec![Key::Val128(self.to_bytes())]
209    }
210}
211
212#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, Copy)]
213pub struct Position {
214    // an account can have a long position and a short position for the same pair at the same time. These two positions
215    // will be represented in two Position entries, with opposite `direction` field.
216    pub direction: PositionDirection,
217    // these values should always be non-negative. A negative value would indicate a bug that breaks certain assumptions
218    pub quantity: SignedDecimal,
219    // the aggregated amount (in price denom) that the account borrowed to establish the position
220    pub total_margin_debt: SignedDecimal,
221    // the aggregated amount (in price denom) that the account paid to establish the position, including both
222    // borrowed fund and out-of-pocket fund
223    pub total_cost: SignedDecimal,
224    // the last time the position has been charged/paid with funding payment (e.g. due to liquidation, etc.)
225    pub last_funding_payment_epoch: i64,
226    // the last paid cumulative funding rate for the position
227    // used to calculate remaining payment amount by finding the difference with the current cumulative funding rate
228    pub last_paid_funding_payment_rate: SignedDecimal,
229}
230
231pub fn opposite_direction(direction: PositionDirection) -> PositionDirection {
232    match direction {
233        PositionDirection::Long => PositionDirection::Short,
234        PositionDirection::Short => PositionDirection::Long,
235        PositionDirection::Unknown => PositionDirection::Unknown,
236    }
237}
238
239#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
240pub struct MarginRatios {
241    pub initial: Decimal,
242    pub partial: Decimal,
243    pub maintenance: Decimal,
244}