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