gmsol_store/states/market/revertible/
market.rs1use std::{borrow::Borrow, cell::RefMut};
2
3use anchor_lang::prelude::*;
4use gmsol_model::{
5 params::{
6 fee::{BorrowingFeeParams, FundingFeeParams},
7 position::PositionImpactDistributionParams,
8 FeeParams, PositionParams, PriceImpactParams,
9 },
10 PoolKind,
11};
12
13use crate::{
14 constants, debug_msg,
15 events::EventEmitter,
16 states::{
17 market::{
18 clock::{AsClock, AsClockMut},
19 Clocks, Pool,
20 },
21 Factor, HasMarketMeta, Market, MarketMeta, OtherState,
22 },
23 CoreError,
24};
25
26use super::{Revertible, Revision};
27
28#[derive(Clone, Copy)]
30pub enum SwapPricingKind {
31 Swap,
33 Deposit,
35 Withdrawal,
37 Shift,
39}
40
41pub struct RevertibleMarket<'a, 'info> {
43 pub(super) market: RefMut<'a, Market>,
44 order_fee_discount_factor: u128,
45 event_emitter: EventEmitter<'a, 'info>,
46 swap_pricing: SwapPricingKind,
47}
48
49impl Key for RevertibleMarket<'_, '_> {
50 fn key(&self) -> Pubkey {
51 self.market.meta.market_token_mint
52 }
53}
54
55impl Revision for RevertibleMarket<'_, '_> {
56 fn rev(&self) -> u64 {
57 self.market.buffer.rev()
58 }
59}
60
61impl AsRef<Market> for RevertibleMarket<'_, '_> {
62 fn as_ref(&self) -> &Market {
63 &self.market
64 }
65}
66
67impl<'a, 'info> RevertibleMarket<'a, 'info> {
68 pub(crate) fn new(
69 market: &'a AccountLoader<'info, Market>,
70 event_emitter: EventEmitter<'a, 'info>,
71 ) -> Result<Self> {
72 let mut market = market.load_mut()?;
73 market.buffer.start_revertible_operation();
74 Ok(Self {
75 market,
76 order_fee_discount_factor: 0,
77 event_emitter,
78 swap_pricing: SwapPricingKind::Swap,
79 })
80 }
81
82 pub(crate) fn with_order_fee_discount_factor(mut self, discount: u128) -> Self {
83 self.order_fee_discount_factor = discount;
84 self
85 }
86
87 pub(crate) fn set_swap_pricing_kind(&mut self, kind: SwapPricingKind) {
88 self.swap_pricing = kind;
89 }
90
91 pub(crate) fn event_emitter(&self) -> &EventEmitter<'a, 'info> {
92 &self.event_emitter
93 }
94
95 fn pool(&self, kind: PoolKind) -> gmsol_model::Result<&Pool> {
96 let Market { state, buffer, .. } = &*self.market;
97 buffer
98 .pool(kind, state)
99 .ok_or(gmsol_model::Error::MissingPoolKind(kind))
100 }
101
102 fn pool_mut(&mut self, kind: PoolKind) -> gmsol_model::Result<&mut Pool> {
103 let Market { state, buffer, .. } = &mut *self.market;
104 buffer
105 .pool_mut(kind, state)
106 .ok_or(gmsol_model::Error::MissingPoolKind(kind))
107 }
108
109 fn other(&self) -> &OtherState {
110 let Market { state, buffer, .. } = &*self.market;
111 buffer.other(state)
112 }
113
114 fn other_mut(&mut self) -> &mut OtherState {
115 let Market { state, buffer, .. } = &mut *self.market;
116 buffer.other_mut(state)
117 }
118
119 fn clocks(&self) -> &Clocks {
120 let Market { state, buffer, .. } = &*self.market;
121 buffer.clocks(state)
122 }
123
124 fn clocks_mut(&mut self) -> &mut Clocks {
125 let Market { state, buffer, .. } = &mut *self.market;
126 buffer.clocks_mut(state)
127 }
128
129 fn balance_for_token(&self, is_long_token: bool) -> u64 {
130 let other = self.other();
131 if is_long_token || self.market.is_pure() {
132 other.long_token_balance
133 } else {
134 other.short_token_balance
135 }
136 }
137
138 fn record_transferred_in(&mut self, is_long_token: bool, amount: u64) -> Result<()> {
140 #[cfg(feature = "debug-msg")]
141 let mint = self.market.meta.market_token_mint;
142 let is_pure = self.market.is_pure();
143 let other = self.other_mut();
144
145 debug_msg!(
146 "[Balance updating] {}: {},{}(+{},{is_long_token})",
147 mint,
148 other.long_token_balance,
149 other.short_token_balance,
150 amount,
151 );
152
153 if is_pure || is_long_token {
154 other.long_token_balance = other
155 .long_token_balance
156 .checked_add(amount)
157 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
158 } else {
159 other.short_token_balance = other
160 .short_token_balance
161 .checked_add(amount)
162 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
163 }
164
165 debug_msg!(
166 "[Balance updated (to be committed)] {}: {},{}",
167 mint,
168 other.long_token_balance,
169 other.short_token_balance
170 );
171 Ok(())
172 }
173
174 fn record_transferred_out(&mut self, is_long_token: bool, amount: u64) -> Result<()> {
176 #[cfg(feature = "debug-msg")]
177 let mint = self.market.meta.market_token_mint;
178 let is_pure = self.market.is_pure();
179 let other = self.other_mut();
180
181 debug_msg!(
182 "[Balance updating] {}: {},{}(-{},{is_long_token})",
183 mint,
184 other.long_token_balance,
185 other.short_token_balance,
186 amount,
187 );
188
189 if is_pure || is_long_token {
190 other.long_token_balance = other
191 .long_token_balance
192 .checked_sub(amount)
193 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
194 } else {
195 other.short_token_balance = other
196 .short_token_balance
197 .checked_sub(amount)
198 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
199 }
200
201 debug_msg!(
202 "[Balance updated (to be committed)] {}: {},{}",
203 mint,
204 other.long_token_balance,
205 other.short_token_balance
206 );
207 Ok(())
208 }
209
210 pub(crate) fn next_trade_id(&mut self) -> Result<u64> {
215 let next_trade_id = self
216 .market
217 .state
218 .other
219 .trade_count
220 .checked_add(1)
221 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
222 self.other_mut().trade_count = next_trade_id;
223 Ok(next_trade_id)
224 }
225}
226
227impl Revertible for RevertibleMarket<'_, '_> {
228 fn commit(mut self) {
229 let Market {
230 meta,
231 state,
232 buffer,
233 ..
234 } = &mut *self.market;
235 buffer.commit_to_storage(state, &meta.market_token_mint, &self.event_emitter);
236 debug_msg!(
237 "[Balance committed] {}: {},{}",
238 meta.market_token_mint,
239 state.other.long_token_balance,
240 state.other.short_token_balance
241 );
242 }
243}
244
245impl HasMarketMeta for RevertibleMarket<'_, '_> {
246 fn is_pure(&self) -> bool {
247 self.market.is_pure()
248 }
249 fn market_meta(&self) -> &MarketMeta {
250 self.market.market_meta()
251 }
252}
253
254impl gmsol_model::Bank<Pubkey> for RevertibleMarket<'_, '_> {
255 type Num = u64;
256
257 fn record_transferred_in_by_token<Q: ?Sized + Borrow<Pubkey>>(
258 &mut self,
259 token: &Q,
260 amount: &Self::Num,
261 ) -> gmsol_model::Result<()> {
262 let is_long_token = self.market.meta.to_token_side(token.borrow())?;
263 self.record_transferred_in(is_long_token, *amount)?;
264 Ok(())
265 }
266
267 fn record_transferred_out_by_token<Q: ?Sized + Borrow<Pubkey>>(
268 &mut self,
269 token: &Q,
270 amount: &Self::Num,
271 ) -> gmsol_model::Result<()> {
272 let is_long_token = self.market.meta.to_token_side(token.borrow())?;
273 self.record_transferred_out(is_long_token, *amount)?;
274 Ok(())
275 }
276
277 fn balance<Q: Borrow<Pubkey> + ?Sized>(&self, token: &Q) -> gmsol_model::Result<Self::Num> {
278 let side = self.market.meta.to_token_side(token.borrow())?;
279 Ok(self.balance_for_token(side))
280 }
281}
282
283impl gmsol_model::BaseMarket<{ constants::MARKET_DECIMALS }> for RevertibleMarket<'_, '_> {
284 type Num = u128;
285
286 type Signed = i128;
287
288 type Pool = Pool;
289
290 fn liquidity_pool(&self) -> gmsol_model::Result<&Self::Pool> {
291 self.pool(PoolKind::Primary)
292 }
293
294 fn claimable_fee_pool(&self) -> gmsol_model::Result<&Self::Pool> {
295 self.pool(PoolKind::ClaimableFee)
296 }
297
298 fn swap_impact_pool(&self) -> gmsol_model::Result<&Self::Pool> {
299 self.pool(PoolKind::SwapImpact)
300 }
301
302 fn open_interest_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
303 self.pool(if is_long {
304 PoolKind::OpenInterestForLong
305 } else {
306 PoolKind::OpenInterestForShort
307 })
308 }
309
310 fn open_interest_in_tokens_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
311 self.pool(if is_long {
312 PoolKind::OpenInterestInTokensForLong
313 } else {
314 PoolKind::OpenInterestInTokensForShort
315 })
316 }
317
318 fn collateral_sum_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
319 self.pool(if is_long {
320 PoolKind::CollateralSumForLong
321 } else {
322 PoolKind::CollateralSumForShort
323 })
324 }
325
326 fn usd_to_amount_divisor(&self) -> Self::Num {
327 self.market.usd_to_amount_divisor()
328 }
329
330 fn max_pool_amount(&self, is_long_token: bool) -> gmsol_model::Result<Self::Num> {
331 self.market.max_pool_amount(is_long_token)
332 }
333
334 fn pnl_factor_config(
335 &self,
336 kind: gmsol_model::PnlFactorKind,
337 is_long: bool,
338 ) -> gmsol_model::Result<Self::Num> {
339 self.market.pnl_factor_config(kind, is_long)
340 }
341
342 fn reserve_factor(&self) -> gmsol_model::Result<Self::Num> {
343 self.market.reserve_factor()
344 }
345
346 fn open_interest_reserve_factor(&self) -> gmsol_model::Result<Self::Num> {
347 self.market.open_interest_reserve_factor()
348 }
349
350 fn max_open_interest(&self, is_long: bool) -> gmsol_model::Result<Self::Num> {
351 self.market.max_open_interest(is_long)
352 }
353
354 fn ignore_open_interest_for_usage_factor(&self) -> gmsol_model::Result<bool> {
355 self.market.ignore_open_interest_for_usage_factor()
356 }
357}
358
359impl gmsol_model::BaseMarketMut<{ constants::MARKET_DECIMALS }> for RevertibleMarket<'_, '_> {
360 fn liquidity_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
361 self.pool_mut(PoolKind::Primary)
362 }
363
364 fn claimable_fee_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
365 self.pool_mut(PoolKind::ClaimableFee)
366 }
367}
368
369impl gmsol_model::SwapMarket<{ constants::MARKET_DECIMALS }> for RevertibleMarket<'_, '_> {
370 fn swap_impact_params(&self) -> gmsol_model::Result<PriceImpactParams<Factor>> {
371 self.market.swap_impact_params()
372 }
373
374 fn swap_fee_params(&self) -> gmsol_model::Result<FeeParams<Factor>> {
375 match self.swap_pricing {
376 SwapPricingKind::Shift => {
377 let params = self.market.swap_fee_params()?;
378 Ok(FeeParams::builder()
379 .fee_receiver_factor(*params.receiver_factor())
380 .positive_impact_fee_factor(0)
381 .negative_impact_fee_factor(0)
382 .build())
383 }
384 SwapPricingKind::Swap => self.market.swap_fee_params(),
385 SwapPricingKind::Deposit | SwapPricingKind::Withdrawal => {
386 self.market.swap_fee_params()
389 }
390 }
391 }
392}
393
394impl gmsol_model::SwapMarketMut<{ constants::MARKET_DECIMALS }> for RevertibleMarket<'_, '_> {
395 fn swap_impact_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
396 self.pool_mut(PoolKind::SwapImpact)
397 }
398}
399
400impl gmsol_model::PositionImpactMarket<{ constants::MARKET_DECIMALS }>
401 for RevertibleMarket<'_, '_>
402{
403 fn position_impact_pool(&self) -> gmsol_model::Result<&Self::Pool> {
404 self.pool(PoolKind::PositionImpact)
405 }
406
407 fn position_impact_params(&self) -> gmsol_model::Result<PriceImpactParams<Self::Num>> {
408 self.market.position_impact_params()
409 }
410
411 fn position_impact_distribution_params(
412 &self,
413 ) -> gmsol_model::Result<PositionImpactDistributionParams<Self::Num>> {
414 self.market.position_impact_distribution_params()
415 }
416
417 fn passed_in_seconds_for_position_impact_distribution(&self) -> gmsol_model::Result<u64> {
418 AsClock::from(&self.clocks().price_impact_distribution).passed_in_seconds()
419 }
420}
421
422impl gmsol_model::PositionImpactMarketMut<{ constants::MARKET_DECIMALS }>
423 for RevertibleMarket<'_, '_>
424{
425 fn position_impact_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
426 self.pool_mut(PoolKind::PositionImpact)
427 }
428
429 fn just_passed_in_seconds_for_position_impact_distribution(
430 &mut self,
431 ) -> gmsol_model::Result<u64> {
432 AsClockMut::from(&mut self.clocks_mut().price_impact_distribution).just_passed_in_seconds()
433 }
434}
435
436impl gmsol_model::BorrowingFeeMarket<{ constants::MARKET_DECIMALS }> for RevertibleMarket<'_, '_> {
437 fn borrowing_factor_pool(&self) -> gmsol_model::Result<&Self::Pool> {
438 self.pool(PoolKind::BorrowingFactor)
439 }
440
441 fn total_borrowing_pool(&self) -> gmsol_model::Result<&Self::Pool> {
442 self.pool(PoolKind::TotalBorrowing)
443 }
444
445 fn borrowing_fee_params(&self) -> gmsol_model::Result<BorrowingFeeParams<Self::Num>> {
446 self.market.borrowing_fee_params()
447 }
448
449 fn passed_in_seconds_for_borrowing(&self) -> gmsol_model::Result<u64> {
450 AsClock::from(&self.clocks().borrowing).passed_in_seconds()
451 }
452
453 fn borrowing_fee_kink_model_params(
454 &self,
455 ) -> gmsol_model::Result<gmsol_model::params::fee::BorrowingFeeKinkModelParams<Self::Num>> {
456 self.market.borrowing_fee_kink_model_params()
457 }
458}
459
460impl gmsol_model::PerpMarket<{ constants::MARKET_DECIMALS }> for RevertibleMarket<'_, '_> {
461 fn funding_factor_per_second(&self) -> &Self::Signed {
462 &self.other().funding_factor_per_second
463 }
464
465 fn funding_amount_per_size_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
466 self.pool(if is_long {
467 PoolKind::FundingAmountPerSizeForLong
468 } else {
469 PoolKind::FundingAmountPerSizeForShort
470 })
471 }
472
473 fn claimable_funding_amount_per_size_pool(
474 &self,
475 is_long: bool,
476 ) -> gmsol_model::Result<&Self::Pool> {
477 self.pool(if is_long {
478 PoolKind::ClaimableFundingAmountPerSizeForLong
479 } else {
480 PoolKind::ClaimableFundingAmountPerSizeForShort
481 })
482 }
483
484 fn funding_amount_per_size_adjustment(&self) -> Self::Num {
485 self.market.funding_amount_per_size_adjustment()
486 }
487
488 fn funding_fee_params(&self) -> gmsol_model::Result<FundingFeeParams<Self::Num>> {
489 self.market.funding_fee_params()
490 }
491
492 fn position_params(&self) -> gmsol_model::Result<PositionParams<Self::Num>> {
493 self.market.position_params()
494 }
495
496 fn order_fee_params(&self) -> gmsol_model::Result<FeeParams<Self::Num>> {
497 let params = self.market.order_fee_params()?;
498 Ok(params.with_discount_factor(self.order_fee_discount_factor))
499 }
500
501 fn min_collateral_factor_for_open_interest_multiplier(
502 &self,
503 is_long: bool,
504 ) -> gmsol_model::Result<Self::Num> {
505 self.market
506 .min_collateral_factor_for_open_interest_multiplier(is_long)
507 }
508
509 fn liquidation_fee_params(
510 &self,
511 ) -> gmsol_model::Result<gmsol_model::params::fee::LiquidationFeeParams<Self::Num>> {
512 self.market.liquidation_fee_params()
513 }
514}
515
516impl gmsol_model::BorrowingFeeMarketMut<{ constants::MARKET_DECIMALS }>
517 for RevertibleMarket<'_, '_>
518{
519 fn just_passed_in_seconds_for_borrowing(&mut self) -> gmsol_model::Result<u64> {
520 AsClockMut::from(&mut self.clocks_mut().borrowing).just_passed_in_seconds()
521 }
522
523 fn borrowing_factor_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
524 self.pool_mut(PoolKind::BorrowingFactor)
525 }
526}
527
528impl gmsol_model::PerpMarketMut<{ constants::MARKET_DECIMALS }> for RevertibleMarket<'_, '_> {
529 fn just_passed_in_seconds_for_funding(&mut self) -> gmsol_model::Result<u64> {
530 AsClockMut::from(&mut self.clocks_mut().funding).just_passed_in_seconds()
531 }
532
533 fn funding_factor_per_second_mut(&mut self) -> &mut Self::Signed {
534 &mut self.other_mut().funding_factor_per_second
535 }
536
537 fn open_interest_pool_mut(&mut self, is_long: bool) -> gmsol_model::Result<&mut Self::Pool> {
538 self.pool_mut(if is_long {
539 PoolKind::OpenInterestForLong
540 } else {
541 PoolKind::OpenInterestForShort
542 })
543 }
544
545 fn open_interest_in_tokens_pool_mut(
546 &mut self,
547 is_long: bool,
548 ) -> gmsol_model::Result<&mut Self::Pool> {
549 self.pool_mut(if is_long {
550 PoolKind::OpenInterestInTokensForLong
551 } else {
552 PoolKind::OpenInterestInTokensForShort
553 })
554 }
555
556 fn funding_amount_per_size_pool_mut(
557 &mut self,
558 is_long: bool,
559 ) -> gmsol_model::Result<&mut Self::Pool> {
560 self.pool_mut(if is_long {
561 PoolKind::FundingAmountPerSizeForLong
562 } else {
563 PoolKind::FundingAmountPerSizeForShort
564 })
565 }
566
567 fn claimable_funding_amount_per_size_pool_mut(
568 &mut self,
569 is_long: bool,
570 ) -> gmsol_model::Result<&mut Self::Pool> {
571 self.pool_mut(if is_long {
572 PoolKind::ClaimableFundingAmountPerSizeForLong
573 } else {
574 PoolKind::ClaimableFundingAmountPerSizeForShort
575 })
576 }
577
578 fn collateral_sum_pool_mut(&mut self, is_long: bool) -> gmsol_model::Result<&mut Self::Pool> {
579 self.pool_mut(if is_long {
580 PoolKind::CollateralSumForLong
581 } else {
582 PoolKind::CollateralSumForShort
583 })
584 }
585
586 fn total_borrowing_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
587 self.pool_mut(PoolKind::TotalBorrowing)
588 }
589}