gmsol_programs/model/
position.rs

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