gmsol_programs/model/
position.rs

1use std::sync::Arc;
2
3use gmsol_model::action::{decrease_position::DecreasePositionSwapType, swap::SwapReport};
4
5use crate::{constants, gmsol_store::accounts::Position};
6
7use super::MarketModel;
8
9/// Position Model.
10#[derive(Debug, Clone)]
11pub struct PositionModel {
12    market: MarketModel,
13    position: Arc<Position>,
14    is_long: bool,
15    is_collateral_token_long: bool,
16}
17
18#[repr(u8)]
19enum PositionKind {
20    #[allow(dead_code)]
21    Uninitialized,
22    Long,
23    Short,
24}
25
26impl Position {
27    /// Return whether the side of the position is long.
28    pub fn try_is_long(&self) -> gmsol_model::Result<bool> {
29        if self.kind == PositionKind::Long as u8 {
30            Ok(true)
31        } else if self.kind == PositionKind::Short as u8 {
32            Ok(false)
33        } else {
34            Err(gmsol_model::Error::InvalidPosition(
35                "uninitialized position",
36            ))
37        }
38    }
39}
40
41impl PositionModel {
42    /// Create from [`MarketModel`] and [`Position`].
43    pub fn new(market: MarketModel, position: Arc<Position>) -> gmsol_model::Result<Self> {
44        let is_long = position.try_is_long()?;
45        let is_collateral_token_long = market.meta.token_side(&position.collateral_token)?;
46        Ok(Self {
47            market,
48            position,
49            is_long,
50            is_collateral_token_long,
51        })
52    }
53
54    fn make_position_mut(&mut self) -> &mut Position {
55        Arc::make_mut(&mut self.position)
56    }
57
58    /// Get position.
59    pub fn position(&self) -> &Position {
60        &self.position
61    }
62}
63
64impl gmsol_model::PositionState<{ constants::MARKET_DECIMALS }> for PositionModel {
65    type Num = u128;
66
67    type Signed = i128;
68
69    fn collateral_amount(&self) -> &Self::Num {
70        &self.position.state.collateral_amount
71    }
72
73    fn size_in_usd(&self) -> &Self::Num {
74        &self.position.state.size_in_usd
75    }
76
77    fn size_in_tokens(&self) -> &Self::Num {
78        &self.position.state.size_in_tokens
79    }
80
81    fn borrowing_factor(&self) -> &Self::Num {
82        &self.position.state.borrowing_factor
83    }
84
85    fn funding_fee_amount_per_size(&self) -> &Self::Num {
86        &self.position.state.funding_fee_amount_per_size
87    }
88
89    fn claimable_funding_fee_amount_per_size(&self, is_long_collateral: bool) -> &Self::Num {
90        if is_long_collateral {
91            &self
92                .position
93                .state
94                .long_token_claimable_funding_amount_per_size
95        } else {
96            &self
97                .position
98                .state
99                .short_token_claimable_funding_amount_per_size
100        }
101    }
102}
103
104impl gmsol_model::PositionStateMut<{ constants::MARKET_DECIMALS }> for PositionModel {
105    fn collateral_amount_mut(&mut self) -> &mut Self::Num {
106        &mut self.make_position_mut().state.collateral_amount
107    }
108
109    fn size_in_usd_mut(&mut self) -> &mut Self::Num {
110        &mut self.make_position_mut().state.size_in_usd
111    }
112
113    fn size_in_tokens_mut(&mut self) -> &mut Self::Num {
114        &mut self.make_position_mut().state.size_in_tokens
115    }
116
117    fn borrowing_factor_mut(&mut self) -> &mut Self::Num {
118        &mut self.make_position_mut().state.borrowing_factor
119    }
120
121    fn funding_fee_amount_per_size_mut(&mut self) -> &mut Self::Num {
122        &mut self.make_position_mut().state.funding_fee_amount_per_size
123    }
124
125    fn claimable_funding_fee_amount_per_size_mut(
126        &mut self,
127        is_long_collateral: bool,
128    ) -> &mut Self::Num {
129        if is_long_collateral {
130            &mut self
131                .make_position_mut()
132                .state
133                .long_token_claimable_funding_amount_per_size
134        } else {
135            &mut self
136                .make_position_mut()
137                .state
138                .short_token_claimable_funding_amount_per_size
139        }
140    }
141}
142
143impl gmsol_model::Position<{ constants::MARKET_DECIMALS }> for PositionModel {
144    type Market = MarketModel;
145
146    fn market(&self) -> &Self::Market {
147        &self.market
148    }
149
150    fn is_long(&self) -> bool {
151        self.is_long
152    }
153
154    fn is_collateral_token_long(&self) -> bool {
155        self.is_collateral_token_long
156    }
157
158    fn are_pnl_and_collateral_tokens_the_same(&self) -> bool {
159        self.is_long == self.is_collateral_token_long || self.market.is_pure()
160    }
161
162    fn on_validate(&self) -> gmsol_model::Result<()> {
163        Ok(())
164    }
165}
166
167impl gmsol_model::PositionMut<{ constants::MARKET_DECIMALS }> for PositionModel {
168    fn market_mut(&mut self) -> &mut Self::Market {
169        &mut self.market
170    }
171
172    fn on_increased(&mut self) -> gmsol_model::Result<()> {
173        Ok(())
174    }
175
176    fn on_decreased(&mut self) -> gmsol_model::Result<()> {
177        Ok(())
178    }
179
180    fn on_swapped(
181        &mut self,
182        _ty: DecreasePositionSwapType,
183        _report: &SwapReport<Self::Num, <Self::Num as gmsol_model::num::Unsigned>::Signed>,
184    ) -> gmsol_model::Result<()> {
185        Ok(())
186    }
187
188    fn on_swap_error(
189        &mut self,
190        _ty: DecreasePositionSwapType,
191        _error: gmsol_model::Error,
192    ) -> gmsol_model::Result<()> {
193        Ok(())
194    }
195}