gmsol_store/states/market/revertible/
liquidity_market.rs1use 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
16pub 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 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 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}