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 pub fn update(&mut self, new_state: &PositionState, force_update: bool) -> bool {
90 let position = &mut self.position;
91
92 if !force_update && new_state.trade_id <= position.state.trade_id {
93 return false;
94 }
95 Arc::make_mut(position).state = *new_state;
96
97 true
98 }
99
100 pub fn market_model(&self) -> &MarketModel {
102 &self.market
103 }
104
105 pub fn set_market_model(&mut self, market: &MarketModel) {
107 self.market = market.clone();
108 }
109}
110
111impl gmsol_model::PositionState<{ constants::MARKET_DECIMALS }> for PositionState {
112 type Num = u128;
113
114 type Signed = i128;
115
116 fn collateral_amount(&self) -> &Self::Num {
117 &self.collateral_amount
118 }
119
120 fn size_in_usd(&self) -> &Self::Num {
121 &self.size_in_usd
122 }
123
124 fn size_in_tokens(&self) -> &Self::Num {
125 &self.size_in_tokens
126 }
127
128 fn borrowing_factor(&self) -> &Self::Num {
129 &self.borrowing_factor
130 }
131
132 fn funding_fee_amount_per_size(&self) -> &Self::Num {
133 &self.funding_fee_amount_per_size
134 }
135
136 fn claimable_funding_fee_amount_per_size(&self, is_long_collateral: bool) -> &Self::Num {
137 if is_long_collateral {
138 &self.long_token_claimable_funding_amount_per_size
139 } else {
140 &self.short_token_claimable_funding_amount_per_size
141 }
142 }
143}
144
145impl gmsol_model::PositionState<{ constants::MARKET_DECIMALS }> for PositionModel {
146 type Num = u128;
147
148 type Signed = i128;
149
150 fn collateral_amount(&self) -> &Self::Num {
151 self.position.state.collateral_amount()
152 }
153
154 fn size_in_usd(&self) -> &Self::Num {
155 self.position.state.size_in_usd()
156 }
157
158 fn size_in_tokens(&self) -> &Self::Num {
159 self.position.state.size_in_tokens()
160 }
161
162 fn borrowing_factor(&self) -> &Self::Num {
163 self.position.state.borrowing_factor()
164 }
165
166 fn funding_fee_amount_per_size(&self) -> &Self::Num {
167 self.position.state.funding_fee_amount_per_size()
168 }
169
170 fn claimable_funding_fee_amount_per_size(&self, is_long_collateral: bool) -> &Self::Num {
171 self.position
172 .state
173 .claimable_funding_fee_amount_per_size(is_long_collateral)
174 }
175}
176
177impl gmsol_model::PositionStateMut<{ constants::MARKET_DECIMALS }> for PositionModel {
178 fn collateral_amount_mut(&mut self) -> &mut Self::Num {
179 &mut self.make_position_mut().state.collateral_amount
180 }
181
182 fn size_in_usd_mut(&mut self) -> &mut Self::Num {
183 &mut self.make_position_mut().state.size_in_usd
184 }
185
186 fn size_in_tokens_mut(&mut self) -> &mut Self::Num {
187 &mut self.make_position_mut().state.size_in_tokens
188 }
189
190 fn borrowing_factor_mut(&mut self) -> &mut Self::Num {
191 &mut self.make_position_mut().state.borrowing_factor
192 }
193
194 fn funding_fee_amount_per_size_mut(&mut self) -> &mut Self::Num {
195 &mut self.make_position_mut().state.funding_fee_amount_per_size
196 }
197
198 fn claimable_funding_fee_amount_per_size_mut(
199 &mut self,
200 is_long_collateral: bool,
201 ) -> &mut Self::Num {
202 if is_long_collateral {
203 &mut self
204 .make_position_mut()
205 .state
206 .long_token_claimable_funding_amount_per_size
207 } else {
208 &mut self
209 .make_position_mut()
210 .state
211 .short_token_claimable_funding_amount_per_size
212 }
213 }
214}
215
216impl gmsol_model::Position<{ constants::MARKET_DECIMALS }> for PositionModel {
217 type Market = MarketModel;
218
219 fn market(&self) -> &Self::Market {
220 &self.market
221 }
222
223 fn is_long(&self) -> bool {
224 self.is_long
225 }
226
227 fn is_collateral_token_long(&self) -> bool {
228 self.is_collateral_token_long
229 }
230
231 fn are_pnl_and_collateral_tokens_the_same(&self) -> bool {
232 self.is_long == self.is_collateral_token_long || self.market.is_pure()
233 }
234
235 fn on_validate(&self) -> gmsol_model::Result<()> {
236 Ok(())
237 }
238}
239
240impl gmsol_model::PositionMut<{ constants::MARKET_DECIMALS }> for PositionModel {
241 fn market_mut(&mut self) -> &mut Self::Market {
242 &mut self.market
243 }
244
245 fn on_increased(&mut self) -> gmsol_model::Result<()> {
246 Ok(())
247 }
248
249 fn on_decreased(&mut self) -> gmsol_model::Result<()> {
250 Ok(())
251 }
252
253 fn on_swapped(
254 &mut self,
255 _ty: DecreasePositionSwapType,
256 report: &SwapReport<Self::Num, <Self::Num as gmsol_model::num::Unsigned>::Signed>,
257 ) -> gmsol_model::Result<()> {
258 self.swap_history.push(Arc::new(report.clone()));
259 Ok(())
260 }
261
262 fn on_swap_error(
263 &mut self,
264 _ty: DecreasePositionSwapType,
265 _error: gmsol_model::Error,
266 ) -> gmsol_model::Result<()> {
267 Ok(())
268 }
269}