gmsol_programs/model/
position.rs1use 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#[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 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 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 pub fn position(&self) -> &Position {
65 &self.position
66 }
67
68 pub fn position_arc(&self) -> &Arc<Position> {
70 &self.position
71 }
72
73 pub fn swap_history(&self) -> &[Arc<SwapReport<u128, i128>>] {
75 &self.swap_history
76 }
77
78 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}