1use std::str::FromStr;
29
30use anchor_lang::{prelude::*, Bump};
31use anchor_spl::token::Mint;
32use borsh::{BorshDeserialize, BorshSerialize};
33use config::MarketConfigFlag;
34use gmsol_model::{
35 num::Unsigned, price::Prices, Balance, BaseMarket, BaseMarketExt, ClockKind, Delta, PoolKind,
36};
37use gmsol_utils::{
38 market::{MarketError, MarketFlag, MAX_MARKET_FLAGS},
39 pubkey::{optional_address, DEFAULT_PUBKEY},
40 token_config::TokenMapAccess,
41};
42use pool::cancel_amounts;
43use revertible::RevertibleBuffer;
44use virtual_inventory::VirtualInventory;
45
46use crate::{
47 constants::MARKET_DECIMALS,
48 utils::fixed_str::{bytes_to_fixed_str, fixed_str_to_bytes},
49 CoreError, ModelError,
50};
51
52use super::{Factor, InitSpace, Oracle, Seed};
53
54use self::{
55 config::{MarketConfig, MarketConfigBuffer, MarketConfigKey},
56 pool::{Pool, Pools},
57};
58
59pub use gmsol_utils::market::{HasMarketMeta, MarketMeta};
60pub use model::AsLiquidityMarket;
61
62pub mod utils;
64
65pub mod clock;
67
68pub mod config;
70
71pub mod revertible;
73
74pub mod pool;
76
77pub mod status;
79
80pub mod virtual_inventory;
82
83mod model;
84
85const MAX_NAME_LEN: usize = 64;
86
87#[account(zero_copy)]
89#[cfg_attr(feature = "debug", derive(Debug))]
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91pub struct Market {
92 version: u8,
93 pub(crate) bump: u8,
95 flags: MarketFlagContainer,
96 padding: [u8; 5],
97 closed_state_updated_at: i64,
98 #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
99 name: [u8; MAX_NAME_LEN],
100 pub(crate) meta: MarketMeta,
101 pub store: Pubkey,
103 config: MarketConfig,
104 indexer: Indexer,
105 state: State,
106 buffer: RevertibleBuffer,
107 virtual_inventory_for_swaps: Pubkey,
108 virtual_inventory_for_positions: Pubkey,
109 #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
110 reserved: [u8; 192],
111}
112
113#[zero_copy]
114#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116struct State {
117 pools: Pools,
118 clocks: Clocks,
119 other: OtherState,
120 #[cfg_attr(feature = "debug", debug(skip))]
121 #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
122 reserved: [u8; 1024],
123}
124
125impl Bump for Market {
126 fn seed(&self) -> u8 {
127 self.bump
128 }
129}
130
131impl Seed for Market {
132 const SEED: &'static [u8] = b"market";
133}
134
135impl InitSpace for Market {
136 const INIT_SPACE: usize = std::mem::size_of::<Self>();
137}
138
139impl Default for Market {
140 fn default() -> Self {
141 use bytemuck::Zeroable;
142 Self::zeroed()
143 }
144}
145
146impl AsRef<Market> for Market {
147 fn as_ref(&self) -> &Market {
148 self
149 }
150}
151
152impl Market {
153 pub fn find_market_address(
155 store: &Pubkey,
156 token: &Pubkey,
157 store_program_id: &Pubkey,
158 ) -> (Pubkey, u8) {
159 Pubkey::find_program_address(
160 &[Self::SEED, store.as_ref(), token.as_ref()],
161 store_program_id,
162 )
163 }
164
165 #[allow(clippy::too_many_arguments)]
167 pub fn init(
168 &mut self,
169 bump: u8,
170 store: Pubkey,
171 name: &str,
172 market_token_mint: Pubkey,
173 index_token_mint: Pubkey,
174 long_token_mint: Pubkey,
175 short_token_mint: Pubkey,
176 is_enabled: bool,
177 ) -> Result<()> {
178 self.bump = bump;
179 self.store = store;
180 self.name = fixed_str_to_bytes(name)?;
181 self.set_enabled(is_enabled);
182 self.meta.market_token_mint = market_token_mint;
183 self.meta.index_token_mint = index_token_mint;
184 self.meta.long_token_mint = long_token_mint;
185 self.meta.short_token_mint = short_token_mint;
186 let is_pure = self.meta.long_token_mint == self.meta.short_token_mint;
187 self.set_flag(MarketFlag::Pure, is_pure);
188 self.state.pools.init(is_pure);
189 self.state.clocks.init_to_current()?;
190 self.config.init();
191
192 self.buffer.init();
194 Ok(())
195 }
196
197 pub fn meta(&self) -> &MarketMeta {
199 &self.meta
200 }
201
202 pub fn validated_meta(&self, store: &Pubkey) -> Result<&MarketMeta> {
204 self.validated_meta_with_options(store, false)
205 }
206
207 pub(crate) fn validated_meta_with_options(
209 &self,
210 store: &Pubkey,
211 allow_closed: bool,
212 ) -> Result<&MarketMeta> {
213 self.validate_with_options(store, allow_closed)?;
214 Ok(self.meta())
215 }
216
217 pub fn name(&self) -> Result<&str> {
219 bytes_to_fixed_str(&self.name)
220 }
221
222 pub fn description(&self) -> Result<String> {
224 let name = self.name()?;
225 Ok(format!(
226 "Market {{ name = {name}, token = {}}}",
227 self.meta.market_token_mint
228 ))
229 }
230
231 pub fn flag(&self, flag: MarketFlag) -> bool {
233 self.flags.get_flag(flag)
234 }
235
236 pub fn set_flag(&mut self, flag: MarketFlag, value: bool) -> bool {
240 self.flags.set_flag(flag, value)
241 }
242
243 pub fn is_pure(&self) -> bool {
245 self.flag(MarketFlag::Pure)
246 }
247
248 pub fn is_enabled(&self) -> bool {
250 self.flag(MarketFlag::Enabled)
251 }
252
253 pub fn set_enabled(&mut self, enabled: bool) -> bool {
257 self.set_flag(MarketFlag::Enabled, enabled)
258 }
259
260 pub fn is_adl_enabled(&self, is_long: bool) -> bool {
262 if is_long {
263 self.flag(MarketFlag::AutoDeleveragingEnabledForLong)
264 } else {
265 self.flag(MarketFlag::AutoDeleveragingEnabledForShort)
266 }
267 }
268
269 pub fn set_adl_enabled(&mut self, is_long: bool, enabled: bool) -> bool {
273 if is_long {
274 self.set_flag(MarketFlag::AutoDeleveragingEnabledForLong, enabled)
275 } else {
276 self.set_flag(MarketFlag::AutoDeleveragingEnabledForShort, enabled)
277 }
278 }
279
280 pub fn is_gt_minting_enabled(&self) -> bool {
282 self.flag(MarketFlag::GTEnabled)
283 }
284
285 pub fn set_is_gt_minting_enabled(&mut self, enabled: bool) -> bool {
289 self.set_flag(MarketFlag::GTEnabled, enabled)
290 }
291
292 pub fn is_closed(&self) -> bool {
294 self.flag(MarketFlag::Closed)
295 }
296
297 pub(crate) fn set_closed(&mut self, closed: bool) -> Result<bool> {
301 let clock = Clock::get()?;
302 self.closed_state_updated_at = clock.unix_timestamp;
303 Ok(self.set_flag(MarketFlag::Closed, closed))
304 }
305
306 #[inline]
308 pub fn pool(&self, kind: PoolKind) -> Option<Pool> {
309 self.state.pools.get(kind).map(|s| s.pool()).copied()
310 }
311
312 pub fn try_pool(&self, kind: PoolKind) -> gmsol_model::Result<&Pool> {
314 Ok(self
315 .state
316 .pools
317 .get(kind)
318 .ok_or(gmsol_model::Error::MissingPoolKind(kind))?
319 .pool())
320 }
321
322 pub fn clock(&self, kind: ClockKind) -> Option<i64> {
324 self.state.clocks.get(kind).copied()
325 }
326
327 fn clocks(&self) -> &Clocks {
328 &self.state.clocks
329 }
330
331 pub fn validate(&self, store: &Pubkey) -> Result<()> {
333 self.validate_with_options(store, false)
334 }
335
336 pub(crate) fn validate_with_options(&self, store: &Pubkey, allow_closed: bool) -> Result<()> {
338 require_keys_eq!(*store, self.store, CoreError::StoreMismatched);
339 require!(self.is_enabled(), CoreError::DisabledMarket);
340 if !allow_closed {
341 require!(!self.is_closed(), CoreError::MarketClosed);
342 }
343 Ok(())
344 }
345
346 pub fn get_config(&self, key: &str) -> Result<&Factor> {
348 let key = MarketConfigKey::from_str(key)
349 .map_err(|_| error!(CoreError::InvalidMarketConfigKey))?;
350 self.get_config_by_key(key)
351 .ok_or_else(|| error!(CoreError::Unimplemented))
352 }
353
354 #[inline]
356 pub fn get_config_by_key(&self, key: MarketConfigKey) -> Option<&Factor> {
357 self.config.get(key)
358 }
359
360 pub fn get_config_mut(&mut self, key: &str) -> Result<&mut Factor> {
362 let key = MarketConfigKey::from_str(key)
363 .map_err(|_| error!(CoreError::InvalidMarketConfigKey))?;
364 self.get_config_by_key_mut(key)
365 }
366
367 pub(crate) fn get_config_by_key_mut(&mut self, key: MarketConfigKey) -> Result<&mut Factor> {
369 self.config
370 .get_mut(key)
371 .ok_or_else(|| error!(CoreError::Unimplemented))
372 }
373
374 pub fn get_config_flag(&self, key: &str) -> Result<bool> {
376 let key = MarketConfigFlag::from_str(key)
377 .map_err(|_| error!(CoreError::InvalidMarketConfigKey))?;
378 Ok(self.get_config_flag_by_key(key))
379 }
380
381 #[inline]
383 pub fn get_config_flag_by_key(&self, key: MarketConfigFlag) -> bool {
384 self.config.flag(key)
385 }
386
387 pub fn set_config_flag(&mut self, key: &str, value: bool) -> Result<bool> {
391 let key = MarketConfigFlag::from_str(key)
392 .map_err(|_| error!(CoreError::InvalidMarketConfigKey))?;
393 Ok(self.set_config_flag_by_key(key, value))
394 }
395
396 pub(crate) fn set_config_flag_by_key(&mut self, key: MarketConfigFlag, value: bool) -> bool {
400 self.config.set_flag(key, value)
401 }
402
403 pub fn state(&self) -> &OtherState {
405 &self.state.other
406 }
407
408 pub fn indexer(&self) -> &Indexer {
410 &self.indexer
411 }
412
413 pub fn indexer_mut(&mut self) -> &mut Indexer {
415 &mut self.indexer
416 }
417
418 pub fn update_config_with_buffer(&mut self, buffer: &MarketConfigBuffer) -> Result<()> {
420 for entry in buffer.iter() {
421 let key = entry.key()?;
422 let current_value = self
423 .config
424 .get_mut(key)
425 .ok_or_else(|| error!(CoreError::Unimplemented))?;
426 let new_value = entry.value();
427 *current_value = new_value;
428 }
429 Ok(())
430 }
431
432 pub fn prices(&self, oracle: &Oracle) -> Result<Prices<u128>> {
434 oracle.market_prices(self)
435 }
436
437 pub fn max_pool_value_for_deposit(&self, is_long_token: bool) -> gmsol_model::Result<Factor> {
439 if is_long_token {
440 Ok(self.config.max_pool_value_for_deposit_for_long_token)
441 } else {
442 Ok(self.config.max_pool_value_for_deposit_for_short_token)
443 }
444 }
445
446 pub fn as_liquidity_market<'a>(
448 &'a self,
449 market_token: &'a Mint,
450 ) -> AsLiquidityMarket<'a, Self> {
451 AsLiquidityMarket::new(self, market_token)
452 }
453
454 pub fn validate_shiftable(&self, target: &Self) -> Result<()> {
456 require_keys_eq!(
463 self.meta().long_token_mint,
464 target.meta().long_token_mint,
465 CoreError::TokenMintMismatched,
466 );
467
468 require_keys_eq!(
469 self.meta().short_token_mint,
470 target.meta().short_token_mint,
471 CoreError::TokenMintMismatched,
472 );
473
474 Ok(())
475 }
476
477 pub fn virtual_inventory_for_swaps(&self) -> Option<&Pubkey> {
479 optional_address(&self.virtual_inventory_for_swaps)
480 }
481
482 pub fn join_virtual_inventory_for_swaps_unchecked(
489 &mut self,
490 address: &Pubkey,
491 virtual_inventory_for_swaps: &mut VirtualInventory,
492 token_map: &impl TokenMapAccess,
493 ) -> Result<()> {
494 require_keys_neq!(*address, DEFAULT_PUBKEY);
495 require!(
496 self.virtual_inventory_for_swaps().is_none(),
497 CoreError::PreconditionsAreNotMet
498 );
499 let long_amount_decimals = token_map
500 .get(&self.meta().long_token_mint)
501 .ok_or_else(|| {
502 msg!("long token not found in the token map");
503 error!(CoreError::Internal)
504 })?
505 .token_decimals();
506 let short_amount_decimals = token_map
507 .get(&self.meta().short_token_mint)
508 .ok_or_else(|| {
509 msg!("short token not found in the token map");
510 error!(CoreError::Internal)
511 })?
512 .token_decimals();
513 require!(
514 virtual_inventory_for_swaps.decimals() == (long_amount_decimals, short_amount_decimals),
515 CoreError::InvalidArgument,
516 );
517 self.virtual_inventory_for_swaps = *address;
518 let liquidity_pool = self.liquidity_pool().map_err(ModelError::from)?;
519 virtual_inventory_for_swaps.join_unchecked(Delta::new_both_sides(
520 true,
521 &(liquidity_pool
522 .long_amount()
523 .map_err(ModelError::from)?
524 .try_into()
525 .map_err(|_| error!(CoreError::TokenAmountOverflow))?),
526 &(liquidity_pool
527 .short_amount()
528 .map_err(ModelError::from)?
529 .try_into()
530 .map_err(|_| error!(CoreError::TokenAmountOverflow))?),
531 ))?;
532 Ok(())
533 }
534
535 pub fn leave_virtual_inventory_for_swaps_unchecked(
540 &mut self,
541 virtual_inventory_for_swaps: &mut VirtualInventory,
542 ) -> Result<()> {
543 require!(
544 self.virtual_inventory_for_swaps().is_some(),
545 CoreError::PreconditionsAreNotMet
546 );
547 let liquidity_pool = self.liquidity_pool().map_err(ModelError::from)?;
548 virtual_inventory_for_swaps.leave_unchecked(Delta::new_both_sides(
549 true,
550 &(liquidity_pool
551 .long_amount()
552 .map_err(ModelError::from)?
553 .to_opposite_signed()
554 .map_err(ModelError::from)?),
555 &(liquidity_pool
556 .short_amount()
557 .map_err(ModelError::from)?
558 .to_opposite_signed()
559 .map_err(ModelError::from)?),
560 ))?;
561 self.virtual_inventory_for_swaps = DEFAULT_PUBKEY;
562 Ok(())
563 }
564
565 pub fn leave_disabled_virtual_inventory_unchecked(
570 &mut self,
571 address: &Pubkey,
572 virtual_inventory: &mut VirtualInventory,
573 ) -> Result<()> {
574 require!(
575 virtual_inventory.is_disabled(),
576 CoreError::PreconditionsAreNotMet
577 );
578
579 if self.virtual_inventory_for_swaps() == Some(address) {
580 self.virtual_inventory_for_swaps = DEFAULT_PUBKEY;
581 } else if self.virtual_inventory_for_positions() == Some(address) {
582 self.virtual_inventory_for_positions = DEFAULT_PUBKEY;
583 }
584
585 virtual_inventory.leave_unchecked(Delta::new(None, None))?;
586
587 Ok(())
588 }
589
590 pub fn virtual_inventory_for_positions(&self) -> Option<&Pubkey> {
592 optional_address(&self.virtual_inventory_for_positions)
593 }
594
595 pub fn join_virtual_inventory_for_positions_unchecked(
601 &mut self,
602 address: &Pubkey,
603 virtual_inventory_for_positions: &mut VirtualInventory,
604 ) -> Result<()> {
605 require_keys_neq!(*address, DEFAULT_PUBKEY);
606 require!(
607 self.virtual_inventory_for_positions().is_none(),
608 CoreError::PreconditionsAreNotMet
609 );
610 require!(
611 virtual_inventory_for_positions.decimals() == (MARKET_DECIMALS, MARKET_DECIMALS),
612 CoreError::Internal
613 );
614 self.virtual_inventory_for_positions = *address;
615 let open_interest = self.open_interest().map_err(ModelError::from)?;
616 let (long_amount, short_amount) = cancel_amounts(
617 open_interest.long_amount().map_err(ModelError::from)?,
618 open_interest.short_amount().map_err(ModelError::from)?,
619 );
620 virtual_inventory_for_positions.join_unchecked(Delta::new_both_sides(
621 true,
622 &(long_amount
623 .try_into()
624 .map_err(|_| error!(CoreError::TokenAmountOverflow))?),
625 &(short_amount
626 .try_into()
627 .map_err(|_| error!(CoreError::TokenAmountOverflow))?),
628 ))?;
629 virtual_inventory_for_positions.cancel_amounts_unchecked()?;
630 Ok(())
631 }
632
633 pub fn leave_virtual_inventory_for_positions_unchecked(
638 &mut self,
639 virtual_inventory_for_positions: &mut VirtualInventory,
640 ) -> Result<()> {
641 require!(
642 self.virtual_inventory_for_positions().is_some(),
643 CoreError::PreconditionsAreNotMet
644 );
645 let open_interest = self.open_interest().map_err(ModelError::from)?;
646 let (long_amount, short_amount) = cancel_amounts(
647 open_interest.long_amount().map_err(ModelError::from)?,
648 open_interest.short_amount().map_err(ModelError::from)?,
649 );
650 virtual_inventory_for_positions.leave_unchecked(Delta::new_both_sides(
651 false,
652 &(long_amount
653 .try_into()
654 .map_err(|_| error!(CoreError::TokenAmountOverflow))?),
655 &(short_amount
656 .try_into()
657 .map_err(|_| error!(CoreError::TokenAmountOverflow))?),
658 ))?;
659 virtual_inventory_for_positions.cancel_amounts_unchecked()?;
660 self.virtual_inventory_for_positions = DEFAULT_PUBKEY;
661 Ok(())
662 }
663}
664
665gmsol_utils::flags!(MarketFlag, MAX_MARKET_FLAGS, u8);
666
667#[zero_copy]
669#[derive(BorshSerialize, BorshDeserialize, InitSpace)]
670#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
671#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
672pub struct OtherState {
673 #[cfg_attr(feature = "debug", debug(skip))]
674 padding: [u8; 16],
675 rev: u64,
676 trade_count: u64,
677 long_token_balance: u64,
678 short_token_balance: u64,
679 funding_factor_per_second: i128,
680 #[cfg_attr(feature = "debug", debug(skip))]
681 #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
682 reserved: [u8; 256],
683}
684
685impl OtherState {
686 pub fn long_token_balance_raw(&self) -> u64 {
688 self.long_token_balance
689 }
690
691 pub fn short_token_balance_raw(&self) -> u64 {
693 self.short_token_balance
694 }
695
696 pub fn funding_factor_per_second(&self) -> i128 {
698 self.funding_factor_per_second
699 }
700
701 pub fn trade_count(&self) -> u64 {
703 self.trade_count
704 }
705
706 pub fn next_trade_id(&mut self) -> Result<u64> {
708 let next_id = self
709 .trade_count
710 .checked_add(1)
711 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
712 self.trade_count = next_id;
713 Ok(next_id)
714 }
715}
716
717impl HasMarketMeta for Market {
718 fn is_pure(&self) -> bool {
719 self.is_pure()
720 }
721
722 fn market_meta(&self) -> &MarketMeta {
723 &self.meta
724 }
725}
726
727#[zero_copy]
729#[derive(BorshSerialize, BorshDeserialize, InitSpace)]
730#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
731#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
732pub struct Clocks {
733 #[cfg_attr(feature = "debug", debug(skip))]
734 padding: [u8; 8],
735 rev: u64,
736 price_impact_distribution: i64,
738 borrowing: i64,
740 funding: i64,
742 adl_for_long: i64,
744 adl_for_short: i64,
746 #[cfg_attr(feature = "debug", debug(skip))]
747 reserved: [i64; 3],
748}
749
750impl Clocks {
751 fn init_to_current(&mut self) -> Result<()> {
752 let current = Clock::get()?.unix_timestamp;
753 self.price_impact_distribution = current;
754 self.borrowing = current;
755 self.funding = current;
756 Ok(())
757 }
758
759 fn get(&self, kind: ClockKind) -> Option<&i64> {
760 let clock = match kind {
761 ClockKind::PriceImpactDistribution => &self.price_impact_distribution,
762 ClockKind::Borrowing => &self.borrowing,
763 ClockKind::Funding => &self.funding,
764 ClockKind::AdlForLong => &self.adl_for_long,
765 ClockKind::AdlForShort => &self.adl_for_short,
766 _ => return None,
767 };
768 Some(clock)
769 }
770
771 fn get_mut(&mut self, kind: ClockKind) -> Option<&mut i64> {
772 let clock = match kind {
773 ClockKind::PriceImpactDistribution => &mut self.price_impact_distribution,
774 ClockKind::Borrowing => &mut self.borrowing,
775 ClockKind::Funding => &mut self.funding,
776 ClockKind::AdlForLong => &mut self.adl_for_long,
777 ClockKind::AdlForShort => &mut self.adl_for_short,
778 _ => return None,
779 };
780 Some(clock)
781 }
782}
783
784#[zero_copy]
786#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
787#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
788pub struct Indexer {
789 trade_count: u64,
790 deposit_count: u64,
791 withdrawal_count: u64,
792 order_count: u64,
793 shift_count: u64,
794 glv_deposit_count: u64,
795 glv_withdrawal_count: u64,
796 #[cfg_attr(feature = "debug", debug(skip))]
797 padding_0: [u8; 8],
798 #[cfg_attr(feature = "debug", debug(skip))]
799 #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
800 reserved: [u8; 128],
801}
802
803impl Indexer {
804 pub fn deposit_count(&self) -> u64 {
806 self.deposit_count
807 }
808
809 pub fn withdrawal_count(&self) -> u64 {
811 self.withdrawal_count
812 }
813
814 pub fn order_count(&self) -> u64 {
816 self.order_count
817 }
818
819 pub fn shift_count(&self) -> u64 {
821 self.shift_count
822 }
823
824 pub fn glv_deposit_count(&self) -> u64 {
826 self.glv_deposit_count
827 }
828
829 pub fn glv_withdrawal_count(&self) -> u64 {
831 self.glv_withdrawal_count
832 }
833
834 pub fn next_deposit_id(&mut self) -> Result<u64> {
836 let next_id = self
837 .deposit_count
838 .checked_add(1)
839 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
840 self.deposit_count = next_id;
841 Ok(next_id)
842 }
843
844 pub fn next_withdrawal_id(&mut self) -> Result<u64> {
846 let next_id = self
847 .withdrawal_count
848 .checked_add(1)
849 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
850 self.withdrawal_count = next_id;
851 Ok(next_id)
852 }
853
854 pub fn next_order_id(&mut self) -> Result<u64> {
856 let next_id = self
857 .order_count
858 .checked_add(1)
859 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
860 self.order_count = next_id;
861 Ok(next_id)
862 }
863
864 pub fn next_shift_id(&mut self) -> Result<u64> {
866 let next_id = self
867 .shift_count
868 .checked_add(1)
869 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
870 self.shift_count = next_id;
871 Ok(next_id)
872 }
873
874 pub fn next_glv_deposit_id(&mut self) -> Result<u64> {
876 let next_id = self
877 .glv_deposit_count
878 .checked_add(1)
879 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
880 self.glv_deposit_count = next_id;
881 Ok(next_id)
882 }
883
884 pub fn next_glv_withdrawal_id(&mut self) -> Result<u64> {
886 let next_id = self
887 .glv_withdrawal_count
888 .checked_add(1)
889 .ok_or_else(|| error!(CoreError::TokenAmountOverflow))?;
890 self.glv_withdrawal_count = next_id;
891 Ok(next_id)
892 }
893}
894
895impl From<MarketError> for CoreError {
896 fn from(err: MarketError) -> Self {
897 msg!("Market Error: {}", err);
898 match err {
899 MarketError::NotACollateralToken => Self::InvalidArgument,
900 MarketError::ExceedMaxMarketConfigFactor => Self::InvalidArgument,
901 }
902 }
903}
904
905#[cfg(test)]
906mod tests {
907 use super::*;
908 use crate::events::{EventClocks, EventOtherState};
909
910 #[test]
911 fn test_event_clocks() {
912 let clocks = Clocks {
913 padding: Default::default(),
914 rev: u64::MAX,
915 price_impact_distribution: i64::MAX,
916 borrowing: i64::MAX,
917 funding: i64::MAX,
918 adl_for_long: i64::MAX,
919 adl_for_short: i64::MAX,
920 reserved: Default::default(),
921 };
922
923 let event_clocks = EventClocks {
924 padding: clocks.padding,
925 rev: clocks.rev,
926 price_impact_distribution: clocks.price_impact_distribution,
927 borrowing: clocks.borrowing,
928 funding: clocks.funding,
929 adl_for_long: clocks.adl_for_long,
930 adl_for_short: clocks.adl_for_short,
931 reserved: clocks.reserved,
932 };
933
934 let mut data = Vec::with_capacity(Pool::INIT_SPACE);
935 clocks
936 .serialize(&mut data)
937 .expect("failed to serialize `Clocks`");
938
939 let mut event_data = Vec::with_capacity(Pool::INIT_SPACE);
940 event_clocks
941 .serialize(&mut event_data)
942 .expect("failed to serialize `EventClocks`");
943
944 assert_eq!(data, event_data);
945 }
946
947 #[test]
948 fn test_event_other_state() {
949 let clocks = OtherState {
950 padding: Default::default(),
951 rev: u64::MAX,
952 trade_count: u64::MAX,
953 long_token_balance: u64::MAX,
954 short_token_balance: u64::MAX,
955 funding_factor_per_second: i128::MAX,
956 reserved: [0; 256],
957 };
958
959 let event_clocks = EventOtherState {
960 padding: clocks.padding,
961 rev: clocks.rev,
962 trade_count: clocks.trade_count,
963 long_token_balance: clocks.long_token_balance,
964 short_token_balance: clocks.short_token_balance,
965 funding_factor_per_second: clocks.funding_factor_per_second,
966 reserved: clocks.reserved,
967 };
968
969 let mut data = Vec::with_capacity(Pool::INIT_SPACE);
970 clocks
971 .serialize(&mut data)
972 .expect("failed to serialize `OtherState`");
973
974 let mut event_data = Vec::with_capacity(Pool::INIT_SPACE);
975 event_clocks
976 .serialize(&mut event_data)
977 .expect("failed to serialize `EventOtherState`");
978
979 assert_eq!(data, event_data);
980 }
981}