levana_perpswap_cosmos/
direction.rs

1//! Different representations of the direction of a position.
2//!
3//! Positions can either be long or short, but due to the different
4//! [MarketType]s supported by perps we need to distinguish between the
5//! direction to the base asset versus the notional asset.
6use std::array::TryFromSliceError;
7use std::convert::From;
8
9use cosmwasm_schema::cw_serde;
10use cosmwasm_std::{StdError, StdResult};
11use cw_storage_plus::{IntKey, Key, KeyDeserialize, Prefixer, PrimaryKey};
12
13use crate::{market_type::MarketType, prelude::*};
14
15/// Direction in terms of notional
16#[cw_serde]
17#[derive(Eq, Copy)]
18#[repr(u8)]
19pub enum DirectionToNotional {
20    /// Long versus notional
21    Long,
22    /// Short versus notional
23    Short,
24}
25
26/// Direction in terms of base
27#[cw_serde]
28#[derive(Eq, Copy)]
29#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
30pub enum DirectionToBase {
31    /// Long versus base
32    Long,
33    /// Short versus base
34    Short,
35}
36
37impl DirectionToBase {
38    /// Represent as a string, either `long` or `short`
39    pub const fn as_str(&self) -> &'static str {
40        match self {
41            Self::Long => "long",
42            Self::Short => "short",
43        }
44    }
45
46    /// Swap to the opposite direction
47    pub fn invert(self) -> Self {
48        match self {
49            Self::Long => Self::Short,
50            Self::Short => Self::Long,
51        }
52    }
53
54    /// Convert into the direction to notional
55    pub fn into_notional(&self, market_type: MarketType) -> DirectionToNotional {
56        match (market_type, self) {
57            (MarketType::CollateralIsQuote, DirectionToBase::Long) => DirectionToNotional::Long,
58            (MarketType::CollateralIsQuote, DirectionToBase::Short) => DirectionToNotional::Short,
59            (MarketType::CollateralIsBase, DirectionToBase::Long) => DirectionToNotional::Short,
60            (MarketType::CollateralIsBase, DirectionToBase::Short) => DirectionToNotional::Long,
61        }
62    }
63}
64
65impl DirectionToNotional {
66    /// Represent as a string, either `long` or `short`
67    pub const fn as_str(&self) -> &'static str {
68        match self {
69            Self::Long => "long",
70            Self::Short => "short",
71        }
72    }
73
74    /// Convert into the direction to base
75    pub fn into_base(&self, market_type: MarketType) -> DirectionToBase {
76        match (market_type, self) {
77            (MarketType::CollateralIsQuote, DirectionToNotional::Long) => DirectionToBase::Long,
78            (MarketType::CollateralIsQuote, DirectionToNotional::Short) => DirectionToBase::Short,
79            (MarketType::CollateralIsBase, DirectionToNotional::Long) => DirectionToBase::Short,
80            (MarketType::CollateralIsBase, DirectionToNotional::Short) => DirectionToBase::Long,
81        }
82    }
83
84    /// Return positive 1 for long, negative 1 for short
85    pub fn sign(&self) -> Number {
86        match self {
87            DirectionToNotional::Long => Number::ONE,
88            DirectionToNotional::Short => Number::NEG_ONE,
89        }
90    }
91}
92
93impl From<DirectionToNotional> for u8 {
94    fn from(value: DirectionToNotional) -> Self {
95        match value {
96            DirectionToNotional::Long => 0,
97            DirectionToNotional::Short => 1,
98        }
99    }
100}
101
102impl From<&str> for DirectionToNotional {
103    fn from(s: &str) -> Self {
104        match s {
105            "long" => Self::Long,
106            "short" => Self::Short,
107            _ => unimplemented!(),
108        }
109    }
110}
111
112impl<'a> PrimaryKey<'a> for DirectionToNotional {
113    type Prefix = ();
114    type SubPrefix = ();
115    type Suffix = Self;
116    type SuperSuffix = Self;
117
118    fn key(&self) -> Vec<Key> {
119        let val: u8 = u8::from(*self);
120        let key = Key::Val8(val.to_cw_bytes());
121
122        vec![key]
123    }
124}
125
126impl<'a> Prefixer<'a> for DirectionToNotional {
127    fn prefix(&self) -> Vec<Key> {
128        let val: u8 = u8::from(*self);
129        let key = Key::Val8(val.to_cw_bytes());
130        vec![key]
131    }
132}
133
134impl KeyDeserialize for DirectionToNotional {
135    type Output = u8;
136
137    const KEY_ELEMS: u16 = 1;
138
139    #[inline(always)]
140    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
141        Ok(u8::from_cw_bytes(value.as_slice().try_into().map_err(
142            |err: TryFromSliceError| StdError::generic_err(err.to_string()),
143        )?))
144    }
145}