1use std::{
2 borrow::Borrow,
3 ops::{Deref, DerefMut},
4 sync::Arc,
5};
6
7use anchor_lang::prelude::Pubkey;
8use bitmaps::Bitmap;
9use gmsol_model::{
10 params::{
11 fee::{
12 BorrowingFeeKinkModelParams, BorrowingFeeKinkModelParamsForOneSide, BorrowingFeeParams,
13 FundingFeeParams, LiquidationFeeParams,
14 },
15 position::PositionImpactDistributionParams,
16 FeeParams, PositionParams, PriceImpactParams,
17 },
18 PoolKind,
19};
20
21use crate::{
22 constants,
23 gmsol_store::{
24 accounts::Market,
25 types::{MarketConfig, MarketMeta, Pool, PoolStorage, Pools},
26 },
27};
28
29use super::clock::{AsClock, AsClockMut};
30
31impl MarketMeta {
32 pub fn token_side(&self, token: &Pubkey) -> gmsol_model::Result<bool> {
34 if *token == self.long_token_mint {
35 Ok(true)
36 } else if *token == self.short_token_mint {
37 Ok(false)
38 } else {
39 Err(gmsol_model::Error::InvalidArgument("not a pool token"))
40 }
41 }
42}
43
44impl Pools {
45 fn get(&self, kind: PoolKind) -> Option<&PoolStorage> {
46 let pool = match kind {
47 PoolKind::Primary => &self.primary,
48 PoolKind::SwapImpact => &self.swap_impact,
49 PoolKind::ClaimableFee => &self.claimable_fee,
50 PoolKind::OpenInterestForLong => &self.open_interest_for_long,
51 PoolKind::OpenInterestForShort => &self.open_interest_for_short,
52 PoolKind::OpenInterestInTokensForLong => &self.open_interest_in_tokens_for_long,
53 PoolKind::OpenInterestInTokensForShort => &self.open_interest_in_tokens_for_short,
54 PoolKind::PositionImpact => &self.position_impact,
55 PoolKind::BorrowingFactor => &self.borrowing_factor,
56 PoolKind::FundingAmountPerSizeForLong => &self.funding_amount_per_size_for_long,
57 PoolKind::FundingAmountPerSizeForShort => &self.funding_amount_per_size_for_short,
58 PoolKind::ClaimableFundingAmountPerSizeForLong => {
59 &self.claimable_funding_amount_per_size_for_long
60 }
61 PoolKind::ClaimableFundingAmountPerSizeForShort => {
62 &self.claimable_funding_amount_per_size_for_short
63 }
64 PoolKind::CollateralSumForLong => &self.collateral_sum_for_long,
65 PoolKind::CollateralSumForShort => &self.collateral_sum_for_short,
66 PoolKind::TotalBorrowing => &self.total_borrowing,
67 _ => return None,
68 };
69 Some(pool)
70 }
71
72 fn get_mut(&mut self, kind: PoolKind) -> Option<&mut PoolStorage> {
73 let pool = match kind {
74 PoolKind::Primary => &mut self.primary,
75 PoolKind::SwapImpact => &mut self.swap_impact,
76 PoolKind::ClaimableFee => &mut self.claimable_fee,
77 PoolKind::OpenInterestForLong => &mut self.open_interest_for_long,
78 PoolKind::OpenInterestForShort => &mut self.open_interest_for_short,
79 PoolKind::OpenInterestInTokensForLong => &mut self.open_interest_in_tokens_for_long,
80 PoolKind::OpenInterestInTokensForShort => &mut self.open_interest_in_tokens_for_short,
81 PoolKind::PositionImpact => &mut self.position_impact,
82 PoolKind::BorrowingFactor => &mut self.borrowing_factor,
83 PoolKind::FundingAmountPerSizeForLong => &mut self.funding_amount_per_size_for_long,
84 PoolKind::FundingAmountPerSizeForShort => &mut self.funding_amount_per_size_for_short,
85 PoolKind::ClaimableFundingAmountPerSizeForLong => {
86 &mut self.claimable_funding_amount_per_size_for_long
87 }
88 PoolKind::ClaimableFundingAmountPerSizeForShort => {
89 &mut self.claimable_funding_amount_per_size_for_short
90 }
91 PoolKind::CollateralSumForLong => &mut self.collateral_sum_for_long,
92 PoolKind::CollateralSumForShort => &mut self.collateral_sum_for_short,
93 PoolKind::TotalBorrowing => &mut self.total_borrowing,
94 _ => return None,
95 };
96 Some(pool)
97 }
98}
99
100#[repr(u8)]
101enum MarketConfigFlag {
102 SkipBorrowingFeeForSmallerSide,
103 IgnoreOpenInterestForUsageFactor,
104}
105
106type MarketConfigFlags = Bitmap<{ constants::NUM_MARKET_CONFIG_FLAGS }>;
107
108impl MarketConfig {
109 fn flag(&self, flag: MarketConfigFlag) -> bool {
110 MarketConfigFlags::from_value(self.flag.value).get(flag as usize)
111 }
112}
113
114#[repr(u8)]
115#[allow(dead_code)]
116enum MarketFlag {
117 Enabled,
118 Pure,
119 AutoDeleveragingEnabledForLong,
120 AutoDeleveragingEnabledForShort,
121 GTEnabled,
122}
123
124type MarketFlags = Bitmap<{ constants::NUM_MARKET_FLAGS }>;
125
126impl Market {
127 fn try_pool(&self, kind: PoolKind) -> gmsol_model::Result<&Pool> {
128 Ok(&self
129 .state
130 .pools
131 .get(kind)
132 .ok_or(gmsol_model::Error::MissingPoolKind(kind))?
133 .pool)
134 }
135
136 fn try_pool_mut(&mut self, kind: PoolKind) -> gmsol_model::Result<&mut Pool> {
137 Ok(&mut self
138 .state
139 .pools
140 .get_mut(kind)
141 .ok_or(gmsol_model::Error::MissingPoolKind(kind))?
142 .pool)
143 }
144
145 fn flag(&self, flag: MarketFlag) -> bool {
146 MarketFlags::from_value(self.flags.value).get(flag as usize)
147 }
148}
149
150#[derive(Debug, Clone)]
152pub struct MarketModel {
153 market: Arc<Market>,
154 supply: u64,
155}
156
157impl Deref for MarketModel {
158 type Target = Market;
159
160 fn deref(&self) -> &Self::Target {
161 &self.market
162 }
163}
164
165impl MarketModel {
166 pub fn from_parts(market: Arc<Market>, supply: u64) -> Self {
168 Self { market, supply }
169 }
170
171 pub fn is_pure(&self) -> bool {
173 self.market.flag(MarketFlag::Pure)
174 }
175
176 fn record_transferred_in(
178 &mut self,
179 is_long_token: bool,
180 amount: u64,
181 ) -> gmsol_model::Result<()> {
182 let is_pure = self.market.flag(MarketFlag::Pure);
183 let other = &self.market.state.other;
184
185 if is_pure || is_long_token {
186 self.make_market_mut().state.other.long_token_balance =
187 other.long_token_balance.checked_add(amount).ok_or(
188 gmsol_model::Error::Computation("increasing long token balance"),
189 )?;
190 } else {
191 self.make_market_mut().state.other.short_token_balance =
192 other.short_token_balance.checked_add(amount).ok_or(
193 gmsol_model::Error::Computation("increasing short token balance"),
194 )?;
195 }
196
197 Ok(())
198 }
199
200 fn record_transferred_out(
202 &mut self,
203 is_long_token: bool,
204 amount: u64,
205 ) -> gmsol_model::Result<()> {
206 let is_pure = self.market.flag(MarketFlag::Pure);
207 let other = &self.market.state.other;
208
209 if is_pure || is_long_token {
210 self.make_market_mut().state.other.long_token_balance =
211 other.long_token_balance.checked_sub(amount).ok_or(
212 gmsol_model::Error::Computation("decreasing long token balance"),
213 )?;
214 } else {
215 self.make_market_mut().state.other.short_token_balance =
216 other.short_token_balance.checked_sub(amount).ok_or(
217 gmsol_model::Error::Computation("decreasing long token balance"),
218 )?;
219 }
220
221 Ok(())
222 }
223
224 fn balance_for_token(&self, is_long_token: bool) -> u64 {
225 let other = &self.state.other;
226 if is_long_token || self.market.flag(MarketFlag::Pure) {
227 other.long_token_balance
228 } else {
229 other.short_token_balance
230 }
231 }
232
233 fn make_market_mut(&mut self) -> &mut Market {
234 Arc::make_mut(&mut self.market)
235 }
236
237 pub fn passed_in_seconds_for_funding(&self) -> gmsol_model::Result<u64> {
239 AsClock::from(&self.state.clocks.funding).passed_in_seconds()
240 }
241}
242
243impl gmsol_model::BaseMarket<{ constants::MARKET_DECIMALS }> for MarketModel {
244 type Num = u128;
245
246 type Signed = i128;
247
248 type Pool = Pool;
249
250 fn liquidity_pool(&self) -> gmsol_model::Result<&Self::Pool> {
251 self.try_pool(PoolKind::Primary)
252 }
253
254 fn claimable_fee_pool(&self) -> gmsol_model::Result<&Self::Pool> {
255 self.try_pool(PoolKind::ClaimableFee)
256 }
257
258 fn swap_impact_pool(&self) -> gmsol_model::Result<&Self::Pool> {
259 self.try_pool(PoolKind::SwapImpact)
260 }
261
262 fn open_interest_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
263 self.try_pool(if is_long {
264 PoolKind::OpenInterestForLong
265 } else {
266 PoolKind::OpenInterestForShort
267 })
268 }
269
270 fn open_interest_in_tokens_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
271 self.try_pool(if is_long {
272 PoolKind::OpenInterestInTokensForLong
273 } else {
274 PoolKind::OpenInterestInTokensForShort
275 })
276 }
277
278 fn collateral_sum_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
279 let kind = if is_long {
280 PoolKind::CollateralSumForLong
281 } else {
282 PoolKind::CollateralSumForShort
283 };
284 self.try_pool(kind)
285 }
286
287 fn virtual_inventory_for_swaps_pool(
288 &self,
289 ) -> gmsol_model::Result<Option<impl Deref<Target = Self::Pool>>> {
290 Ok(None::<&Self::Pool>)
291 }
292
293 fn virtual_inventory_for_positions_pool(
294 &self,
295 ) -> gmsol_model::Result<Option<impl Deref<Target = Self::Pool>>> {
296 Ok(None::<&Self::Pool>)
297 }
298
299 fn usd_to_amount_divisor(&self) -> Self::Num {
300 constants::MARKET_USD_TO_AMOUNT_DIVISOR
301 }
302
303 fn max_pool_amount(&self, is_long_token: bool) -> gmsol_model::Result<Self::Num> {
304 if is_long_token {
305 Ok(self.config.max_pool_amount_for_long_token)
306 } else {
307 Ok(self.config.max_pool_amount_for_short_token)
308 }
309 }
310
311 fn pnl_factor_config(
312 &self,
313 kind: gmsol_model::PnlFactorKind,
314 is_long: bool,
315 ) -> gmsol_model::Result<Self::Num> {
316 use gmsol_model::PnlFactorKind;
317
318 match (kind, is_long) {
319 (PnlFactorKind::MaxAfterDeposit, true) => {
320 Ok(self.config.max_pnl_factor_for_long_deposit)
321 }
322 (PnlFactorKind::MaxAfterDeposit, false) => {
323 Ok(self.config.max_pnl_factor_for_short_deposit)
324 }
325 (PnlFactorKind::MaxAfterWithdrawal, true) => {
326 Ok(self.config.max_pnl_factor_for_long_withdrawal)
327 }
328 (PnlFactorKind::MaxAfterWithdrawal, false) => {
329 Ok(self.config.max_pnl_factor_for_short_withdrawal)
330 }
331 (PnlFactorKind::MaxForTrader, true) => Ok(self.config.max_pnl_factor_for_long_trader),
332 (PnlFactorKind::MaxForTrader, false) => Ok(self.config.max_pnl_factor_for_short_trader),
333 (PnlFactorKind::ForAdl, true) => Ok(self.config.max_pnl_factor_for_long_adl),
334 (PnlFactorKind::ForAdl, false) => Ok(self.config.max_pnl_factor_for_short_adl),
335 (PnlFactorKind::MinAfterAdl, true) => Ok(self.config.min_pnl_factor_after_long_adl),
336 (PnlFactorKind::MinAfterAdl, false) => Ok(self.config.min_pnl_factor_after_short_adl),
337 _ => Err(gmsol_model::Error::InvalidArgument("missing pnl factor")),
338 }
339 }
340
341 fn reserve_factor(&self) -> gmsol_model::Result<Self::Num> {
342 Ok(self.config.reserve_factor)
343 }
344
345 fn open_interest_reserve_factor(&self) -> gmsol_model::Result<Self::Num> {
346 Ok(self.config.open_interest_reserve_factor)
347 }
348
349 fn max_open_interest(&self, is_long: bool) -> gmsol_model::Result<Self::Num> {
350 if is_long {
351 Ok(self.config.max_open_interest_for_long)
352 } else {
353 Ok(self.config.max_open_interest_for_short)
354 }
355 }
356
357 fn ignore_open_interest_for_usage_factor(&self) -> gmsol_model::Result<bool> {
358 Ok(self
359 .config
360 .flag(MarketConfigFlag::IgnoreOpenInterestForUsageFactor))
361 }
362}
363
364impl gmsol_model::SwapMarket<{ constants::MARKET_DECIMALS }> for MarketModel {
365 fn swap_impact_params(&self) -> gmsol_model::Result<PriceImpactParams<Self::Num>> {
366 Ok(PriceImpactParams::builder()
367 .exponent(self.config.swap_impact_exponent)
368 .positive_factor(self.config.swap_impact_positive_factor)
369 .negative_factor(self.config.swap_impact_negative_factor)
370 .build())
371 }
372
373 fn swap_fee_params(&self) -> gmsol_model::Result<FeeParams<Self::Num>> {
374 Ok(FeeParams::builder()
375 .fee_receiver_factor(self.config.swap_fee_receiver_factor)
376 .positive_impact_fee_factor(self.config.swap_fee_factor_for_positive_impact)
377 .negative_impact_fee_factor(self.config.swap_fee_factor_for_negative_impact)
378 .build())
379 }
380}
381
382impl gmsol_model::PositionImpactMarket<{ constants::MARKET_DECIMALS }> for MarketModel {
383 fn position_impact_pool(&self) -> gmsol_model::Result<&Self::Pool> {
384 self.try_pool(PoolKind::PositionImpact)
385 }
386
387 fn position_impact_params(&self) -> gmsol_model::Result<PriceImpactParams<Self::Num>> {
388 let config = &self.config;
389 Ok(PriceImpactParams::builder()
390 .exponent(config.position_impact_exponent)
391 .positive_factor(config.position_impact_positive_factor)
392 .negative_factor(config.position_impact_negative_factor)
393 .build())
394 }
395
396 fn position_impact_distribution_params(
397 &self,
398 ) -> gmsol_model::Result<PositionImpactDistributionParams<Self::Num>> {
399 let config = &self.config;
400 Ok(PositionImpactDistributionParams::builder()
401 .distribute_factor(config.position_impact_distribute_factor)
402 .min_position_impact_pool_amount(config.min_position_impact_pool_amount)
403 .build())
404 }
405
406 fn passed_in_seconds_for_position_impact_distribution(&self) -> gmsol_model::Result<u64> {
407 AsClock::from(&self.state.clocks.price_impact_distribution).passed_in_seconds()
408 }
409}
410
411impl gmsol_model::BorrowingFeeMarket<{ constants::MARKET_DECIMALS }> for MarketModel {
412 fn borrowing_factor_pool(&self) -> gmsol_model::Result<&Self::Pool> {
413 self.try_pool(PoolKind::BorrowingFactor)
414 }
415
416 fn total_borrowing_pool(&self) -> gmsol_model::Result<&Self::Pool> {
417 self.try_pool(PoolKind::TotalBorrowing)
418 }
419
420 fn borrowing_fee_params(&self) -> gmsol_model::Result<BorrowingFeeParams<Self::Num>> {
421 Ok(BorrowingFeeParams::builder()
422 .receiver_factor(self.config.borrowing_fee_receiver_factor)
423 .factor_for_long(self.config.borrowing_fee_factor_for_long)
424 .factor_for_short(self.config.borrowing_fee_factor_for_short)
425 .exponent_for_long(self.config.borrowing_fee_exponent_for_long)
426 .exponent_for_short(self.config.borrowing_fee_exponent_for_short)
427 .skip_borrowing_fee_for_smaller_side(
428 self.config
429 .flag(MarketConfigFlag::SkipBorrowingFeeForSmallerSide),
430 )
431 .build())
432 }
433
434 fn passed_in_seconds_for_borrowing(&self) -> gmsol_model::Result<u64> {
435 AsClock::from(&self.state.clocks.borrowing).passed_in_seconds()
436 }
437
438 fn borrowing_fee_kink_model_params(
439 &self,
440 ) -> gmsol_model::Result<BorrowingFeeKinkModelParams<Self::Num>> {
441 Ok(BorrowingFeeKinkModelParams::builder()
442 .long(
443 BorrowingFeeKinkModelParamsForOneSide::builder()
444 .optimal_usage_factor(self.config.borrowing_fee_optimal_usage_factor_for_long)
445 .base_borrowing_factor(self.config.borrowing_fee_base_factor_for_long)
446 .above_optimal_usage_borrowing_factor(
447 self.config
448 .borrowing_fee_above_optimal_usage_factor_for_long,
449 )
450 .build(),
451 )
452 .short(
453 BorrowingFeeKinkModelParamsForOneSide::builder()
454 .optimal_usage_factor(self.config.borrowing_fee_optimal_usage_factor_for_short)
455 .base_borrowing_factor(self.config.borrowing_fee_base_factor_for_short)
456 .above_optimal_usage_borrowing_factor(
457 self.config
458 .borrowing_fee_above_optimal_usage_factor_for_short,
459 )
460 .build(),
461 )
462 .build())
463 }
464}
465
466impl gmsol_model::PerpMarket<{ constants::MARKET_DECIMALS }> for MarketModel {
467 fn funding_factor_per_second(&self) -> &Self::Signed {
468 &self.state.other.funding_factor_per_second
469 }
470
471 fn funding_amount_per_size_pool(&self, is_long: bool) -> gmsol_model::Result<&Self::Pool> {
472 let kind = if is_long {
473 PoolKind::FundingAmountPerSizeForLong
474 } else {
475 PoolKind::FundingAmountPerSizeForShort
476 };
477 self.try_pool(kind)
478 }
479
480 fn claimable_funding_amount_per_size_pool(
481 &self,
482 is_long: bool,
483 ) -> gmsol_model::Result<&Self::Pool> {
484 let kind = if is_long {
485 PoolKind::ClaimableFundingAmountPerSizeForLong
486 } else {
487 PoolKind::ClaimableFundingAmountPerSizeForShort
488 };
489 self.try_pool(kind)
490 }
491
492 fn funding_amount_per_size_adjustment(&self) -> Self::Num {
493 constants::FUNDING_AMOUNT_PER_SIZE_ADJUSTMENT
494 }
495
496 fn funding_fee_params(&self) -> gmsol_model::Result<FundingFeeParams<Self::Num>> {
497 Ok(FundingFeeParams::builder()
498 .exponent(self.config.funding_fee_exponent)
499 .funding_factor(self.config.funding_fee_factor)
500 .max_factor_per_second(self.config.funding_fee_max_factor_per_second)
501 .min_factor_per_second(self.config.funding_fee_min_factor_per_second)
502 .increase_factor_per_second(self.config.funding_fee_increase_factor_per_second)
503 .decrease_factor_per_second(self.config.funding_fee_decrease_factor_per_second)
504 .threshold_for_stable_funding(self.config.funding_fee_threshold_for_stable_funding)
505 .threshold_for_decrease_funding(self.config.funding_fee_threshold_for_decrease_funding)
506 .build())
507 }
508
509 fn position_params(&self) -> gmsol_model::Result<PositionParams<Self::Num>> {
510 Ok(PositionParams::new(
511 self.config.min_position_size_usd,
512 self.config.min_collateral_value,
513 self.config.min_collateral_factor,
514 self.config.max_positive_position_impact_factor,
515 self.config.max_negative_position_impact_factor,
516 self.config.max_position_impact_factor_for_liquidations,
517 ))
518 }
519
520 fn order_fee_params(&self) -> gmsol_model::Result<FeeParams<Self::Num>> {
521 Ok(FeeParams::builder()
522 .fee_receiver_factor(self.config.order_fee_receiver_factor)
523 .positive_impact_fee_factor(self.config.order_fee_factor_for_positive_impact)
524 .negative_impact_fee_factor(self.config.order_fee_factor_for_negative_impact)
525 .build())
526 }
527
528 fn min_collateral_factor_for_open_interest_multiplier(
529 &self,
530 is_long: bool,
531 ) -> gmsol_model::Result<Self::Num> {
532 if is_long {
533 Ok(self
534 .config
535 .min_collateral_factor_for_open_interest_multiplier_for_long)
536 } else {
537 Ok(self
538 .config
539 .min_collateral_factor_for_open_interest_multiplier_for_short)
540 }
541 }
542
543 fn liquidation_fee_params(&self) -> gmsol_model::Result<LiquidationFeeParams<Self::Num>> {
544 Ok(LiquidationFeeParams::builder()
545 .factor(self.config.liquidation_fee_factor)
546 .receiver_factor(self.config.liquidation_fee_receiver_factor)
547 .build())
548 }
549}
550
551impl gmsol_model::LiquidityMarket<{ constants::MARKET_DECIMALS }> for MarketModel {
552 fn total_supply(&self) -> Self::Num {
553 u128::from(self.supply)
554 }
555
556 fn max_pool_value_for_deposit(&self, is_long_token: bool) -> gmsol_model::Result<Self::Num> {
557 if is_long_token {
558 Ok(self.config.max_pool_value_for_deposit_for_long_token)
559 } else {
560 Ok(self.config.max_pool_value_for_deposit_for_short_token)
561 }
562 }
563}
564
565impl gmsol_model::Bank<Pubkey> for MarketModel {
566 type Num = u64;
567
568 fn record_transferred_in_by_token<Q: ?Sized + Borrow<Pubkey>>(
569 &mut self,
570 token: &Q,
571 amount: &Self::Num,
572 ) -> gmsol_model::Result<()> {
573 let is_long_token = self.market.meta.token_side(token.borrow())?;
574 self.record_transferred_in(is_long_token, *amount)?;
575 Ok(())
576 }
577
578 fn record_transferred_out_by_token<Q: ?Sized + Borrow<Pubkey>>(
579 &mut self,
580 token: &Q,
581 amount: &Self::Num,
582 ) -> gmsol_model::Result<()> {
583 let is_long_token = self.market.meta.token_side(token.borrow())?;
584 self.record_transferred_out(is_long_token, *amount)?;
585 Ok(())
586 }
587
588 fn balance<Q: Borrow<Pubkey> + ?Sized>(&self, token: &Q) -> gmsol_model::Result<Self::Num> {
589 let side = self.market.meta.token_side(token.borrow())?;
590 Ok(self.balance_for_token(side))
591 }
592}
593
594impl gmsol_model::BaseMarketMut<{ constants::MARKET_DECIMALS }> for MarketModel {
595 fn liquidity_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
596 self.make_market_mut().try_pool_mut(PoolKind::Primary)
597 }
598
599 fn claimable_fee_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
600 self.make_market_mut().try_pool_mut(PoolKind::ClaimableFee)
601 }
602
603 fn virtual_inventory_for_swaps_pool_mut(
604 &mut self,
605 ) -> gmsol_model::Result<Option<impl DerefMut<Target = Self::Pool>>> {
606 Ok(None::<&mut Self::Pool>)
607 }
608}
609
610impl gmsol_model::SwapMarketMut<{ constants::MARKET_DECIMALS }> for MarketModel {
611 fn swap_impact_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
612 self.make_market_mut().try_pool_mut(PoolKind::SwapImpact)
613 }
614}
615
616impl gmsol_model::PositionImpactMarketMut<{ constants::MARKET_DECIMALS }> for MarketModel {
617 fn position_impact_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
618 self.make_market_mut()
619 .try_pool_mut(PoolKind::PositionImpact)
620 }
621
622 fn just_passed_in_seconds_for_position_impact_distribution(
623 &mut self,
624 ) -> gmsol_model::Result<u64> {
625 AsClockMut::from(
626 &mut self
627 .make_market_mut()
628 .state
629 .clocks
630 .price_impact_distribution,
631 )
632 .just_passed_in_seconds()
633 }
634}
635
636impl gmsol_model::PerpMarketMut<{ constants::MARKET_DECIMALS }> for MarketModel {
637 fn just_passed_in_seconds_for_funding(&mut self) -> gmsol_model::Result<u64> {
638 AsClockMut::from(&mut self.make_market_mut().state.clocks.funding).just_passed_in_seconds()
639 }
640
641 fn funding_factor_per_second_mut(&mut self) -> &mut Self::Signed {
642 &mut self.make_market_mut().state.other.funding_factor_per_second
643 }
644
645 fn open_interest_pool_mut(&mut self, is_long: bool) -> gmsol_model::Result<&mut Self::Pool> {
646 self.make_market_mut().try_pool_mut(if is_long {
647 PoolKind::OpenInterestForLong
648 } else {
649 PoolKind::OpenInterestForShort
650 })
651 }
652
653 fn open_interest_in_tokens_pool_mut(
654 &mut self,
655 is_long: bool,
656 ) -> gmsol_model::Result<&mut Self::Pool> {
657 self.make_market_mut().try_pool_mut(if is_long {
658 PoolKind::OpenInterestInTokensForLong
659 } else {
660 PoolKind::OpenInterestInTokensForShort
661 })
662 }
663
664 fn funding_amount_per_size_pool_mut(
665 &mut self,
666 is_long: bool,
667 ) -> gmsol_model::Result<&mut Self::Pool> {
668 self.make_market_mut().try_pool_mut(if is_long {
669 PoolKind::FundingAmountPerSizeForLong
670 } else {
671 PoolKind::FundingAmountPerSizeForShort
672 })
673 }
674
675 fn claimable_funding_amount_per_size_pool_mut(
676 &mut self,
677 is_long: bool,
678 ) -> gmsol_model::Result<&mut Self::Pool> {
679 self.make_market_mut().try_pool_mut(if is_long {
680 PoolKind::ClaimableFundingAmountPerSizeForLong
681 } else {
682 PoolKind::ClaimableFundingAmountPerSizeForShort
683 })
684 }
685
686 fn collateral_sum_pool_mut(&mut self, is_long: bool) -> gmsol_model::Result<&mut Self::Pool> {
687 self.make_market_mut().try_pool_mut(if is_long {
688 PoolKind::CollateralSumForLong
689 } else {
690 PoolKind::CollateralSumForShort
691 })
692 }
693
694 fn total_borrowing_pool_mut(&mut self) -> gmsol_model::Result<&mut Self::Pool> {
695 self.make_market_mut()
696 .try_pool_mut(PoolKind::TotalBorrowing)
697 }
698
699 fn virtual_inventory_for_positions_pool_mut(
700 &mut self,
701 ) -> gmsol_model::Result<Option<impl DerefMut<Target = Self::Pool>>> {
702 Ok(None::<&mut Self::Pool>)
703 }
704}
705
706impl gmsol_model::LiquidityMarketMut<{ constants::MARKET_DECIMALS }> for MarketModel {
707 fn mint(&mut self, amount: &Self::Num) -> gmsol_model::Result<()> {
708 let new_mint: u64 = (*amount)
709 .try_into()
710 .map_err(|_| gmsol_model::Error::Overflow)?;
711 let new_supply = self
712 .supply
713 .checked_add(new_mint)
714 .ok_or(gmsol_model::Error::Overflow)?;
715 self.supply = new_supply;
716 Ok(())
717 }
718
719 fn burn(&mut self, amount: &Self::Num) -> gmsol_model::Result<()> {
720 let new_burn: u64 = (*amount)
721 .try_into()
722 .map_err(|_| gmsol_model::Error::Overflow)?;
723 let new_supply = self
724 .supply
725 .checked_sub(new_burn)
726 .ok_or(gmsol_model::Error::Overflow)?;
727 self.supply = new_supply;
728 Ok(())
729 }
730}