gmsol_store/states/market/revertible/
revertible_position.rs

1use 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
15/// Revertible Position.
16pub 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}