gmsol_store/states/market/revertible/
liquidity_market.rs

1use anchor_lang::prelude::*;
2use anchor_spl::token::Mint;
3use gmsol_model::params::{position::PositionImpactDistributionParams, PriceImpactParams};
4
5use crate::{
6    constants,
7    states::{HasMarketMeta, Store},
8    utils::internal::TransferUtils,
9};
10
11use super::{
12    market::{RevertibleMarket, SwapPricingKind},
13    Revertible, Revision,
14};
15
16/// Convert a [`RevertibleMarket`] to a [`LiquidityMarketMut`](gmsol_model::LiquidityMarketMut).
17pub struct RevertibleLiquidityMarket<'a, 'info> {
18    base: RevertibleMarket<'a, 'info>,
19    token_program: &'a AccountInfo<'info>,
20    store: &'a AccountLoader<'info, Store>,
21    market_token: &'a Account<'info, Mint>,
22    receiver: Option<&'a AccountInfo<'info>>,
23    vault: Option<&'a AccountInfo<'info>>,
24    to_mint: u64,
25    to_burn: u64,
26}
27
28impl<'a, 'info> RevertibleLiquidityMarket<'a, 'info> {
29    pub(crate) fn from_revertible_market(
30        market: RevertibleMarket<'a, 'info>,
31        market_token: &'a Account<'info, Mint>,
32        token_program: &'a AccountInfo<'info>,
33        store: &'a AccountLoader<'info, Store>,
34    ) -> Result<Self> {
35        Ok(Self {
36            base: market,
37            token_program,
38            store,
39            market_token,
40            receiver: None,
41            vault: None,
42            to_mint: 0,
43            to_burn: 0,
44        })
45    }
46
47    pub(crate) fn enable_mint(mut self, receiver: &'a AccountInfo<'info>) -> Self {
48        self.receiver = Some(receiver);
49        self
50    }
51
52    pub(crate) fn enable_burn(mut self, vault: &'a AccountInfo<'info>) -> Self {
53        self.vault = Some(vault);
54        self
55    }
56
57    pub(crate) fn with_swap_pricing_kind(mut self, kind: SwapPricingKind) -> Self {
58        self.base.set_swap_pricing_kind(kind);
59        self
60    }
61
62    fn transfer(&self) -> TransferUtils<'a, 'info> {
63        TransferUtils::new(
64            self.token_program.clone(),
65            self.store,
66            self.market_token.to_account_info(),
67        )
68    }
69
70    pub(crate) fn base(&self) -> &RevertibleMarket<'a, 'info> {
71        &self.base
72    }
73
74    pub(crate) fn base_mut(&mut self) -> &mut RevertibleMarket<'a, 'info> {
75        &mut self.base
76    }
77
78    pub(crate) fn market_token(&self) -> &Account<'info, Mint> {
79        self.market_token
80    }
81}
82
83impl Key for RevertibleLiquidityMarket<'_, '_> {
84    fn key(&self) -> Pubkey {
85        self.base.key()
86    }
87}
88
89impl Revision for RevertibleLiquidityMarket<'_, '_> {
90    fn rev(&self) -> u64 {
91        self.base().rev()
92    }
93}
94
95impl HasMarketMeta for RevertibleLiquidityMarket<'_, '_> {
96    fn market_meta(&self) -> &crate::states::MarketMeta {
97        self.base.market_meta()
98    }
99}
100
101impl Revertible for RevertibleLiquidityMarket<'_, '_> {
102    fn commit(self) {
103        if self.to_mint != 0 {
104            self.transfer()
105                .mint_to(self.receiver.expect("mint is not enabled"), self.to_mint)
106                .map_err(|err| panic!("mint error: {err}"))
107                .unwrap();
108        }
109        if self.to_burn != 0 {
110            self.transfer()
111                .burn_from(self.vault.expect("burn is not enabled"), self.to_burn)
112                .map_err(|err| panic!("burn error: {err}"))
113                .unwrap();
114        }
115        self.base.commit();
116    }
117}
118
119impl<'a, 'info> gmsol_model::Bank<Pubkey> for RevertibleLiquidityMarket<'a, 'info> {
120    type Num = <RevertibleMarket<'a, 'info> as gmsol_model::Bank<Pubkey>>::Num;
121
122    fn record_transferred_in_by_token<Q: std::borrow::Borrow<Pubkey> + ?Sized>(
123        &mut self,
124        token: &Q,
125        amount: &Self::Num,
126    ) -> gmsol_model::Result<()> {
127        self.base.record_transferred_in_by_token(token, amount)
128    }
129
130    fn record_transferred_out_by_token<Q: std::borrow::Borrow<Pubkey> + ?Sized>(
131        &mut self,
132        token: &Q,
133        amount: &Self::Num,
134    ) -> gmsol_model::Result<()> {
135        self.base.record_transferred_out_by_token(token, amount)
136    }
137
138    fn balance<Q: std::borrow::Borrow<Pubkey> + ?Sized>(
139        &self,
140        token: &Q,
141    ) -> gmsol_model::Result<Self::Num> {
142        self.base.balance(token)
143    }
144}
145
146impl<'a, 'info> gmsol_model::BaseMarket<{ constants::MARKET_DECIMALS }>
147    for RevertibleLiquidityMarket<'a, 'info>
148{
149    type Num = <RevertibleMarket<'a, 'info> as gmsol_model::BaseMarket<
150        { constants::MARKET_DECIMALS },
151    >>::Num;
152
153    type Signed = <RevertibleMarket<'a, 'info> as gmsol_model::BaseMarket<
154        { constants::MARKET_DECIMALS },
155    >>::Signed;
156
157    type Pool = <RevertibleMarket<'a, 'info> as gmsol_model::BaseMarket<
158        { constants::MARKET_DECIMALS },
159    >>::Pool;
160
161    fn liquidity_pool(&self) -> gmsol_model::Result<&Self::Pool> {
162        self.base.liquidity_pool()
163    }
164
165    fn claimable_fee_pool(&self) -> gmsol_model::Result<&Self::Pool> {
166        self.base.claimable_fee_pool()
167    }
168
169    fn swap_impact_pool(&self) -> gmsol_model::Result<&Self::Pool> {
170        self.base.swap_impact_pool()
171    }
172
173    fn open_interest_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
174        self.base.open_interest_pool(is_long)
175    }
176
177    fn open_interest_in_tokens_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
178        self.base.open_interest_in_tokens_pool(is_long)
179    }
180
181    fn collateral_sum_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
182        self.base.collateral_sum_pool(is_long)
183    }
184
185    fn usd_to_amount_divisor(&self) -> Self::Num {
186        self.base.usd_to_amount_divisor()
187    }
188
189    fn max_pool_amount(&self, is_long_token: bool) -> gmsol_model::Result<Self::Num> {
190        self.base.max_pool_amount(is_long_token)
191    }
192
193    fn pnl_factor_config(
194        &self,
195        kind: gmsol_model::PnlFactorKind,
196        is_long: bool,
197    ) -> gmsol_model::Result<Self::Num> {
198        self.base.pnl_factor_config(kind, is_long)
199    }
200
201    fn reserve_factor(&self) -> gmsol_model::Result<Self::Num> {
202        self.base.reserve_factor()
203    }
204
205    fn open_interest_reserve_factor(&self) -> gmsol_model::Result<Self::Num> {
206        self.base.open_interest_reserve_factor()
207    }
208
209    fn max_open_interest(&self, is_long: bool) -> gmsol_model::Result<Self::Num> {
210        self.base.max_open_interest(is_long)
211    }
212
213    fn ignore_open_interest_for_usage_factor(&self) -> gmsol_model::Result<bool> {
214        self.base.ignore_open_interest_for_usage_factor()
215    }
216}
217
218impl gmsol_model::BaseMarketMut<{ constants::MARKET_DECIMALS }>
219    for RevertibleLiquidityMarket<'_, '_>
220{
221    fn liquidity_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
222        self.base.liquidity_pool_mut()
223    }
224
225    fn claimable_fee_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
226        self.base.claimable_fee_pool_mut()
227    }
228}
229
230impl gmsol_model::SwapMarket<{ constants::MARKET_DECIMALS }> for RevertibleLiquidityMarket<'_, '_> {
231    fn swap_impact_params(&self) -> gmsol_model::Result<PriceImpactParams<Self::Num>> {
232        self.base.swap_impact_params()
233    }
234
235    fn swap_fee_params(&self) -> gmsol_model::Result<gmsol_model::params::FeeParams<Self::Num>> {
236        self.base.swap_fee_params()
237    }
238}
239
240impl gmsol_model::SwapMarketMut<{ constants::MARKET_DECIMALS }>
241    for RevertibleLiquidityMarket<'_, '_>
242{
243    fn swap_impact_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
244        self.base.swap_impact_pool_mut()
245    }
246}
247
248impl gmsol_model::PositionImpactMarket<{ constants::MARKET_DECIMALS }>
249    for RevertibleLiquidityMarket<'_, '_>
250{
251    fn position_impact_pool(&self) -> gmsol_model::Result<&Self::Pool> {
252        self.base.position_impact_pool()
253    }
254
255    fn position_impact_params(&self) -> gmsol_model::Result<PriceImpactParams<Self::Num>> {
256        self.base.position_impact_params()
257    }
258
259    fn position_impact_distribution_params(
260        &self,
261    ) -> gmsol_model::Result<PositionImpactDistributionParams<Self::Num>> {
262        self.base.position_impact_distribution_params()
263    }
264
265    fn passed_in_seconds_for_position_impact_distribution(&self) -> gmsol_model::Result<u64> {
266        self.base
267            .passed_in_seconds_for_position_impact_distribution()
268    }
269}
270
271impl gmsol_model::PositionImpactMarketMut<{ constants::MARKET_DECIMALS }>
272    for RevertibleLiquidityMarket<'_, '_>
273{
274    fn position_impact_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
275        self.base.position_impact_pool_mut()
276    }
277
278    fn just_passed_in_seconds_for_position_impact_distribution(
279        &mut self,
280    ) -> gmsol_model::Result<u64> {
281        self.base
282            .just_passed_in_seconds_for_position_impact_distribution()
283    }
284}
285
286impl gmsol_model::BorrowingFeeMarket<{ constants::MARKET_DECIMALS }>
287    for RevertibleLiquidityMarket<'_, '_>
288{
289    fn borrowing_factor_pool(&self) -> gmsol_model::Result<&Self::Pool> {
290        self.base.borrowing_factor_pool()
291    }
292
293    fn total_borrowing_pool(&self) -> gmsol_model::Result<&Self::Pool> {
294        self.base.total_borrowing_pool()
295    }
296
297    fn borrowing_fee_params(
298        &self,
299    ) -> gmsol_model::Result<gmsol_model::params::fee::BorrowingFeeParams<Self::Num>> {
300        self.base.borrowing_fee_params()
301    }
302
303    fn passed_in_seconds_for_borrowing(&self) -> gmsol_model::Result<u64> {
304        self.base.passed_in_seconds_for_borrowing()
305    }
306
307    fn borrowing_fee_kink_model_params(
308        &self,
309    ) -> gmsol_model::Result<gmsol_model::params::fee::BorrowingFeeKinkModelParams<Self::Num>> {
310        self.base.borrowing_fee_kink_model_params()
311    }
312}
313
314impl gmsol_model::BorrowingFeeMarketMut<{ constants::MARKET_DECIMALS }>
315    for RevertibleLiquidityMarket<'_, '_>
316{
317    fn just_passed_in_seconds_for_borrowing(&mut self) -> gmsol_model::Result<u64> {
318        self.base.just_passed_in_seconds_for_borrowing()
319    }
320
321    fn borrowing_factor_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
322        self.base.borrowing_factor_pool_mut()
323    }
324}
325
326impl gmsol_model::LiquidityMarket<{ constants::MARKET_DECIMALS }>
327    for RevertibleLiquidityMarket<'_, '_>
328{
329    fn total_supply(&self) -> Self::Num {
330        let supply = u128::from(self.market_token.supply);
331        supply
332            .saturating_add(self.to_mint.into())
333            .saturating_sub(self.to_burn.into())
334    }
335
336    fn max_pool_value_for_deposit(&self, is_long_token: bool) -> gmsol_model::Result<Self::Num> {
337        self.base.market.max_pool_value_for_deposit(is_long_token)
338    }
339}
340
341impl gmsol_model::LiquidityMarketMut<{ constants::MARKET_DECIMALS }>
342    for RevertibleLiquidityMarket<'_, '_>
343{
344    fn mint(&mut self, amount: &Self::Num) -> gmsol_model::Result<()> {
345        let new_mint: u64 = (*amount)
346            .try_into()
347            .map_err(|_| gmsol_model::Error::Overflow)?;
348        let to_mint = self
349            .to_mint
350            .checked_add(new_mint)
351            .ok_or(gmsol_model::Error::Overflow)?;
352        // CHECK for overflow.
353        self.market_token
354            .supply
355            .checked_add(to_mint)
356            .ok_or(gmsol_model::Error::Overflow)?;
357        self.to_mint = to_mint;
358        Ok(())
359    }
360
361    fn burn(&mut self, amount: &Self::Num) -> gmsol_model::Result<()> {
362        let new_burn: u64 = (*amount)
363            .try_into()
364            .map_err(|_| gmsol_model::Error::Overflow)?;
365        let to_burn = self
366            .to_burn
367            .checked_add(new_burn)
368            .ok_or(gmsol_model::Error::Overflow)?;
369        // CHECK for underflow.
370        self.market_token
371            .supply
372            .checked_sub(to_burn)
373            .ok_or(gmsol_model::Error::Computation(
374                "not enough market tokens to burn",
375            ))?;
376        self.to_burn = to_burn;
377        Ok(())
378    }
379}