gmsol_store/states/market/
mod.rs

1//! ## Market
2//! A [`Market`](crate::states::Market) in GMX-Solana is defined by three tokens:
3//!
4//! - **Index Token**: The underlying asset that serves as the trading instrument. The price movements
5//!   of this token determine the profit or loss of positions. It does not need to be a real token.
6//! - **Long Token**: The token used to:
7//!   - Collateralize long and short positions
8//!   - Pay profits to long position holders
9//! - **Short Token**: The token used to:
10//!   - Collateralize long and short positions
11//!   - Pay profits to short position holders
12//!
13//! Long token and short token can be the same token, in which case the market
14//! is called a *single-token market*.
15//!
16//! Liquidity Providers (LPs) can provide liquidity to the market by depositing pool tokens (long token
17//! and short token) in exchange for market tokens. These market tokens represent the LP's proportional
18//! share of the market's liquidity pool. The deposited tokens are held in shared token accounts called
19//! *Market Vaults*, with deposited amounts for this market tracked in the market state. LPs can later
20//! redeem their market tokens back for the underlying collateral tokens through withdrawal instructions.
21//!
22//! Traders can open long or short positions using either token as collateral. When opening a position,
23//! the trader deposits collateral tokens and specifies the desired leverage. The position's profit or
24//! loss is determined by price movements of the index token. The loss is incurred in the collateral
25//! token used to open the position while the profit is realized in the long token and short token
26//! respectively.
27
28use 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
62/// Market Utils.
63pub mod utils;
64
65/// Clock ops.
66pub mod clock;
67
68/// Market Config.
69pub mod config;
70
71/// Revertible Market Operations.
72pub mod revertible;
73
74/// Pool.
75pub mod pool;
76
77/// Market Status.
78pub mod status;
79
80/// Virtual Inventory.
81pub mod virtual_inventory;
82
83mod model;
84
85const MAX_NAME_LEN: usize = 64;
86
87/// Market.
88#[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    /// Bump Seed.
94    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    /// Store.
102    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    /// Find PDA for [`Market`] account.
154    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    /// Initialize the market.
166    #[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        // Initialize buffer.
193        self.buffer.init();
194        Ok(())
195    }
196
197    /// Get meta.
198    pub fn meta(&self) -> &MarketMeta {
199        &self.meta
200    }
201
202    /// Get validated meta.
203    pub fn validated_meta(&self, store: &Pubkey) -> Result<&MarketMeta> {
204        self.validated_meta_with_options(store, false)
205    }
206
207    /// Get validated meta with options.
208    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    /// Get name.
218    pub fn name(&self) -> Result<&str> {
219        bytes_to_fixed_str(&self.name)
220    }
221
222    /// Description.
223    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    /// Get flag.
232    pub fn flag(&self, flag: MarketFlag) -> bool {
233        self.flags.get_flag(flag)
234    }
235
236    /// Set flag.
237    ///
238    /// Return the previous value.
239    pub fn set_flag(&mut self, flag: MarketFlag, value: bool) -> bool {
240        self.flags.set_flag(flag, value)
241    }
242
243    /// Is this market a pure market, i.e., a single token market.
244    pub fn is_pure(&self) -> bool {
245        self.flag(MarketFlag::Pure)
246    }
247
248    /// Is this market enabled.
249    pub fn is_enabled(&self) -> bool {
250        self.flag(MarketFlag::Enabled)
251    }
252
253    /// Set enabled.
254    ///
255    /// Return previous value.
256    pub fn set_enabled(&mut self, enabled: bool) -> bool {
257        self.set_flag(MarketFlag::Enabled, enabled)
258    }
259
260    /// Is ADL enabled.
261    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    /// Set ADL enabled.
270    ///
271    /// Return previous value.
272    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    /// Is GT Minting enabled.
281    pub fn is_gt_minting_enabled(&self) -> bool {
282        self.flag(MarketFlag::GTEnabled)
283    }
284
285    /// Set whether the GT minting is enabled.
286    ///
287    /// Return the previous value.
288    pub fn set_is_gt_minting_enabled(&mut self, enabled: bool) -> bool {
289        self.set_flag(MarketFlag::GTEnabled, enabled)
290    }
291
292    /// Returns whether the market is closed.
293    pub fn is_closed(&self) -> bool {
294        self.flag(MarketFlag::Closed)
295    }
296
297    /// Set whether the market is closed.
298    ///
299    /// Return previous value.
300    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    /// Get pool of the given kind.
307    #[inline]
308    pub fn pool(&self, kind: PoolKind) -> Option<Pool> {
309        self.state.pools.get(kind).map(|s| s.pool()).copied()
310    }
311
312    /// Try to get pool of the given kind.
313    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    /// Get clock of the given kind.
323    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    /// Validate the market.
332    pub fn validate(&self, store: &Pubkey) -> Result<()> {
333        self.validate_with_options(store, false)
334    }
335
336    /// Validate the market with options.
337    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    /// Get config.
347    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    /// Get config by key.
355    #[inline]
356    pub fn get_config_by_key(&self, key: MarketConfigKey) -> Option<&Factor> {
357        self.config.get(key)
358    }
359
360    /// Get config mutably.
361    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    /// Get config mutably by key.
368    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    /// Get config flag.
375    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    /// Get config flag by key.
382    #[inline]
383    pub fn get_config_flag_by_key(&self, key: MarketConfigFlag) -> bool {
384        self.config.flag(key)
385    }
386
387    /// Set config flag.
388    ///
389    /// Returns previous value.
390    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    /// Set config flag by key.
397    ///
398    /// Returns previous value.
399    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    /// Get other market state.
404    pub fn state(&self) -> &OtherState {
405        &self.state.other
406    }
407
408    /// Get market indexer.
409    pub fn indexer(&self) -> &Indexer {
410        &self.indexer
411    }
412
413    /// Get market indexer mutably.
414    pub fn indexer_mut(&mut self) -> &mut Indexer {
415        &mut self.indexer
416    }
417
418    /// Update config with buffer.
419    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    /// Get prices from oracle.
433    pub fn prices(&self, oracle: &Oracle) -> Result<Prices<u128>> {
434        oracle.market_prices(self)
435    }
436
437    /// Get max pool value for deposit.
438    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    /// As a liquidity market.
447    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    /// Validate that this market is shiftable to the target market.
455    pub fn validate_shiftable(&self, target: &Self) -> Result<()> {
456        // Currently we only support the shift between markets with
457        // with the same long tokens and short tokens.
458        //
459        // It should be possible to allow shift between markets with the compatible tokens in the future,
460        // for example, allowing shifting from BTC[WSOL-USDC] to SOL[USDC-WSOL].
461
462        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    /// Returns the address of virtual inventory for swaps.
478    pub fn virtual_inventory_for_swaps(&self) -> Option<&Pubkey> {
479        optional_address(&self.virtual_inventory_for_swaps)
480    }
481
482    /// Join a virtual inventory for swaps.
483    ///
484    /// # CHECK
485    /// - The provided [`VirtualInventory`] must be used as a
486    ///   virtual inventory for swaps.
487    /// - The provided token map must be authorized.
488    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    /// Leave the virtual inventory for swaps.
536    ///
537    /// # CHECK
538    /// - The provided [`VirtualInventory`] must be the associated one.
539    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    /// Leave a disabled virtual inventory.
566    ///
567    /// # CHECK
568    /// - The address and the provided [`VirtualInventory`] must match.
569    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    /// Returns the address of virtual inventory for positions.
591    pub fn virtual_inventory_for_positions(&self) -> Option<&Pubkey> {
592        optional_address(&self.virtual_inventory_for_positions)
593    }
594
595    /// Join a virtual inventory for positions.
596    ///
597    /// # CHECK
598    /// - The provided [`VirtualInventory`] must be used as a
599    ///   virtual inventory for positions.
600    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    /// Leave the virtual inventory for positions.
634    ///
635    /// # CHECK
636    /// - The provided [`VirtualInventory`] must be the associated one.
637    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/// Market State.
668#[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    /// Get long token balance.
687    pub fn long_token_balance_raw(&self) -> u64 {
688        self.long_token_balance
689    }
690
691    /// Get short token balance.
692    pub fn short_token_balance_raw(&self) -> u64 {
693        self.short_token_balance
694    }
695
696    /// Get funding factor per second.
697    pub fn funding_factor_per_second(&self) -> i128 {
698        self.funding_factor_per_second
699    }
700
701    /// Get current trade count.
702    pub fn trade_count(&self) -> u64 {
703        self.trade_count
704    }
705
706    /// Next trade id.
707    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/// Market clocks.
728#[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 clock.
737    price_impact_distribution: i64,
738    /// Borrowing clock.
739    borrowing: i64,
740    /// Funding clock.
741    funding: i64,
742    /// ADL updated clock for long.
743    adl_for_long: i64,
744    /// ADL updated clock for short.
745    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/// Market indexer.
785#[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    /// Get current deposit count.
805    pub fn deposit_count(&self) -> u64 {
806        self.deposit_count
807    }
808
809    /// Get current withdrawal count.
810    pub fn withdrawal_count(&self) -> u64 {
811        self.withdrawal_count
812    }
813
814    /// Get current order count.
815    pub fn order_count(&self) -> u64 {
816        self.order_count
817    }
818
819    /// Get current shift count.
820    pub fn shift_count(&self) -> u64 {
821        self.shift_count
822    }
823
824    /// Get current GLV deposit count.
825    pub fn glv_deposit_count(&self) -> u64 {
826        self.glv_deposit_count
827    }
828
829    /// Get current GLV withdrawal count.
830    pub fn glv_withdrawal_count(&self) -> u64 {
831        self.glv_withdrawal_count
832    }
833
834    /// Next deposit id.
835    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    /// Next withdrawal id.
845    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    /// Next order id.
855    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    /// Next shift id.
865    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    /// Next GLV deposit id.
875    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    /// Next GLV withdrawal id.
885    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}