gmsol_store/states/market/revertible/
revertible_position.rs1use std::cell::RefMut;
2
3use anchor_lang::prelude::*;
4use gmsol_model::{action::decrease_position::DecreasePositionSwapType, num::Unsigned};
5
6use crate::{
7 constants,
8 events::{EventEmitter, SwapExecuted, TradeData},
9 states::{market::revertible::Revision, position::PositionState, HasMarketMeta, Position},
10 CoreError,
11};
12
13use super::{market::RevertibleMarket, Revertible};
14
15pub struct RevertiblePosition<'a, 'info> {
17 market: RevertibleMarket<'a, 'info>,
18 storage: RefMut<'a, Position>,
19 state: PositionState,
20 is_collateral_token_long: bool,
21 is_long: bool,
22}
23
24impl<'a, 'info> RevertiblePosition<'a, 'info> {
25 pub(crate) fn new(
26 market: RevertibleMarket<'a, 'info>,
27 loader: &'a AccountLoader<'info, Position>,
28 ) -> Result<Self> {
29 let storage = loader.load_mut()?;
30 let meta = market.market_meta();
31
32 require_keys_eq!(
33 storage.market_token,
34 meta.market_token_mint,
35 CoreError::MarketTokenMintMismatched
36 );
37
38 let is_long = storage.try_is_long()?;
39 let is_collateral_token_long = meta
40 .to_token_side(&storage.collateral_token)
41 .map_err(CoreError::from)?;
42
43 Ok(Self {
44 is_long,
45 is_collateral_token_long,
46 state: storage.state,
47 market,
48 storage,
49 })
50 }
51
52 pub(crate) fn collateral_token(&self) -> &Pubkey {
53 &self.storage.collateral_token
54 }
55
56 pub(crate) fn write_to_event(&self, event: &mut TradeData) -> Result<()> {
57 event.update_with_state(&self.state)
58 }
59
60 pub(crate) fn event_emitter(&self) -> &EventEmitter<'a, 'info> {
61 self.market.event_emitter()
62 }
63}
64
65impl Revertible for RevertiblePosition<'_, '_> {
66 fn commit(mut self) {
67 self.market.commit();
68 self.storage.state = self.state;
69 }
70}
71
72impl gmsol_model::PositionState<{ constants::MARKET_DECIMALS }> for RevertiblePosition<'_, '_> {
73 type Num = u128;
74
75 type Signed = i128;
76
77 fn collateral_amount(&self) -> &Self::Num {
78 &self.state.collateral_amount
79 }
80
81 fn size_in_usd(&self) -> &Self::Num {
82 self.state.size_in_usd()
83 }
84
85 fn size_in_tokens(&self) -> &Self::Num {
86 self.state.size_in_tokens()
87 }
88
89 fn borrowing_factor(&self) -> &Self::Num {
90 self.state.borrowing_factor()
91 }
92
93 fn funding_fee_amount_per_size(&self) -> &Self::Num {
94 self.state.funding_fee_amount_per_size()
95 }
96
97 fn claimable_funding_fee_amount_per_size(&self, is_long_collateral: bool) -> &Self::Num {
98 self.state
99 .claimable_funding_fee_amount_per_size(is_long_collateral)
100 }
101}
102
103impl<'a, 'info> gmsol_model::Position<{ constants::MARKET_DECIMALS }>
104 for RevertiblePosition<'a, 'info>
105{
106 type Market = RevertibleMarket<'a, 'info>;
107
108 fn market(&self) -> &Self::Market {
109 &self.market
110 }
111
112 fn is_long(&self) -> bool {
113 self.is_long
114 }
115
116 fn is_collateral_token_long(&self) -> bool {
117 self.is_collateral_token_long
118 }
119
120 fn are_pnl_and_collateral_tokens_the_same(&self) -> bool {
121 self.is_long == self.is_collateral_token_long || self.market.is_pure()
122 }
123
124 fn on_validate(&self) -> gmsol_model::Result<()> {
125 self.storage.validate_for_market(&self.market.market)
126 }
127}
128
129impl gmsol_model::PositionMut<{ constants::MARKET_DECIMALS }> for RevertiblePosition<'_, '_> {
130 fn market_mut(&mut self) -> &mut Self::Market {
131 &mut self.market
132 }
133
134 fn on_increased(&mut self) -> gmsol_model::Result<()> {
135 let clock = Clock::get().map_err(Error::from)?;
136 self.state.updated_at_slot = clock.slot;
137 self.state.increased_at = clock.unix_timestamp;
138 self.state.trade_id = self.market.next_trade_id()?;
139 Ok(())
140 }
141
142 fn on_decreased(&mut self) -> gmsol_model::Result<()> {
143 let clock = Clock::get().map_err(Error::from)?;
144 self.state.updated_at_slot = clock.slot;
145 self.state.decreased_at = clock.unix_timestamp;
146 self.state.trade_id = self.market.next_trade_id()?;
147 Ok(())
148 }
149
150 fn on_swapped(
151 &mut self,
152 ty: DecreasePositionSwapType,
153 report: &gmsol_model::action::swap::SwapReport<Self::Num, <Self::Num as Unsigned>::Signed>,
154 ) -> gmsol_model::Result<()> {
155 msg!("[Decrease Position Swap] swapped");
156 let market_token = self.market.market_meta().market_token_mint;
157 self.event_emitter().emit_cpi(&SwapExecuted::new(
158 self.market.rev(),
159 market_token,
160 report.clone(),
161 Some(ty),
162 ))?;
163 Ok(())
164 }
165
166 fn on_swap_error(
167 &mut self,
168 ty: DecreasePositionSwapType,
169 error: gmsol_model::Error,
170 ) -> gmsol_model::Result<()> {
171 msg!("[Decrease Position Swap] error: ty={}, err={}", ty, error);
172 Ok(())
173 }
174}
175
176impl gmsol_model::PositionStateMut<{ constants::MARKET_DECIMALS }> for RevertiblePosition<'_, '_> {
177 fn collateral_amount_mut(&mut self) -> &mut Self::Num {
178 self.state.collateral_amount_mut()
179 }
180
181 fn size_in_usd_mut(&mut self) -> &mut Self::Num {
182 self.state.size_in_usd_mut()
183 }
184
185 fn size_in_tokens_mut(&mut self) -> &mut Self::Num {
186 self.state.size_in_tokens_mut()
187 }
188
189 fn borrowing_factor_mut(&mut self) -> &mut Self::Num {
190 self.state.borrowing_factor_mut()
191 }
192
193 fn funding_fee_amount_per_size_mut(&mut self) -> &mut Self::Num {
194 self.state.funding_fee_amount_per_size_mut()
195 }
196
197 fn claimable_funding_fee_amount_per_size_mut(
198 &mut self,
199 is_long_collateral: bool,
200 ) -> &mut Self::Num {
201 self.state
202 .claimable_funding_fee_amount_per_size_mut(is_long_collateral)
203 }
204}