gmsol_store/states/
store.rs

1use std::{num::NonZeroU64, str::FromStr};
2
3use anchor_lang::{prelude::*, solana_program::last_restart_slot::LastRestartSlot};
4use bytemuck::Zeroable;
5use gmsol_utils::to_seed;
6
7use crate::{constants, states::feature::display_feature, CoreError, CoreResult};
8
9use super::{
10    feature::{ActionDisabledFlag, DisabledFeatures, DomainDisabledFlag},
11    gt::GtState,
12    Amount, Factor, InitSpace, RoleKey, RoleStore, Seed,
13};
14
15pub use gmsol_utils::config::{AddressKey, AmountKey, FactorKey};
16
17const MAX_LEN: usize = 32;
18
19/// Data Store.
20#[account(zero_copy)]
21#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
22pub struct Store {
23    version: u8,
24    bump: [u8; 1],
25    key_seed: [u8; 32],
26    key: [u8; MAX_LEN],
27    #[cfg_attr(feature = "debug", debug(skip))]
28    padding_0: [u8; 6],
29    role: RoleStore,
30    /// Store authority.
31    pub authority: Pubkey,
32    /// Next authority.
33    pub(crate) next_authority: Pubkey,
34    /// The token map to used.
35    pub token_map: Pubkey,
36    /// Disabled features.
37    disabled_features: DisabledFeatures,
38    #[cfg_attr(feature = "debug", debug(skip))]
39    padding_1: [u8; 4],
40    /// Cached last cluster restart slot.
41    last_restarted_slot: u64,
42    /// Treasury Config.
43    treasury: Treasury,
44    /// Amounts.
45    pub(crate) amount: Amounts,
46    #[cfg_attr(feature = "debug", debug(skip))]
47    padding_2: [u8; 8],
48    /// Factors.
49    pub(crate) factor: Factors,
50    /// Addresses.
51    pub(crate) address: Addresses,
52    /// GT State.
53    gt: GtState,
54    #[cfg_attr(feature = "debug", debug(skip))]
55    reserved: [u8; 1024],
56}
57
58static_assertions::const_assert!(Store::INIT_SPACE + 8 <= 10240);
59
60impl InitSpace for Store {
61    const INIT_SPACE: usize = std::mem::size_of::<Self>();
62}
63
64impl Seed for Store {
65    /// The value of the seed is `b"data_store"`
66    const SEED: &'static [u8] = b"data_store";
67}
68
69#[cfg(feature = "display")]
70impl std::fmt::Display for Store {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        write!(
73            f,
74            "Store({}): authority={} roles={} members={} token_map={} treasury={}",
75            self.key()
76                .map(|s| if s.is_empty() { "*default*" } else { s })
77                .unwrap_or("*failed to parse*"),
78            self.authority,
79            self.role.num_roles(),
80            self.role.num_members(),
81            self.token_map()
82                .map(|pubkey| pubkey.to_string())
83                .unwrap_or("*unset*".to_string()),
84            self.treasury,
85        )
86    }
87}
88
89impl Store {
90    /// Maximum length of key.
91    pub const MAX_LEN: usize = MAX_LEN;
92
93    /// Wallet Seed.
94    pub const WALLET_SEED: &'static [u8] = b"store_wallet";
95
96    /// Initialize.
97    pub fn init(
98        &mut self,
99        authority: Pubkey,
100        key: &str,
101        bump: u8,
102        receiver: Pubkey,
103        holding: Pubkey,
104    ) -> Result<()> {
105        self.key = crate::utils::fixed_str::fixed_str_to_bytes(key)?;
106        self.key_seed = to_seed(key);
107        self.bump = [bump];
108        self.authority = authority;
109        self.next_authority = authority;
110        self.treasury.init(receiver);
111        self.amount.init();
112        self.factor.init();
113        self.address.init(holding);
114
115        self.update_last_restarted_slot(false)?;
116
117        Ok(())
118    }
119
120    pub(crate) fn signer_seeds(&self) -> [&[u8]; 3] {
121        [Self::SEED, &self.key_seed, &self.bump]
122    }
123
124    /// Get the role store.
125    pub fn role(&self) -> &RoleStore {
126        &self.role
127    }
128
129    /// Get the key of the store.
130    pub fn key(&self) -> Result<&str> {
131        crate::utils::fixed_str::bytes_to_fixed_str(&self.key)
132    }
133
134    /// Enable a role.
135    pub fn enable_role(&mut self, role: &str) -> Result<()> {
136        self.role.enable_role(role)
137    }
138
139    /// Disable a role.
140    pub fn disable_role(&mut self, role: &str) -> Result<()> {
141        self.role.disable_role(role)
142    }
143
144    /// Check if the roles has the given enabled role.
145    /// Returns `true` only when the `role` is enabled and the `roles` has that role.
146    ///
147    /// # Note
148    /// - If the cluster [has restarted](Self::has_restarted), this function returns `true` if and only if
149    ///   the `authority` has the [`RESTART_ADMIN`](RoleKey::RESTART_ADMIN) role.
150    pub fn has_role(&self, authority: &Pubkey, role: &str) -> Result<bool> {
151        if self.has_restarted()? {
152            if self.role.has_role(authority, RoleKey::RESTART_ADMIN)? {
153                Ok(true)
154            } else {
155                err!(CoreError::StoreOutdated)
156            }
157        } else {
158            self.role.has_role(authority, role)
159        }
160    }
161
162    /// Grant a role.
163    pub fn grant(&mut self, authority: &Pubkey, role: &str) -> Result<()> {
164        self.role.grant(authority, role)
165    }
166
167    /// Revoke a role.
168    pub fn revoke(&mut self, authority: &Pubkey, role: &str) -> Result<()> {
169        self.role.revoke(authority, role)
170    }
171
172    /// Check if the given pubkey is the authority of the store.
173    pub fn is_authority(&self, authority: &Pubkey) -> bool {
174        self.authority == *authority
175    }
176
177    /// Check if the given authority has the ADMIN role.
178    ///
179    /// # Note
180    /// - If the cluster [has restarted](Self::has_restarted), addresses with the
181    ///   [`RESTART_ADMIN`](RoleKey::RESTART_ADMIN) role also have the ADMIN role.
182    pub fn has_admin_role(&self, authority: &Pubkey) -> Result<bool> {
183        if self.is_authority(authority) {
184            Ok(true)
185        } else if self.has_restarted()? {
186            self.role.has_role(authority, RoleKey::RESTART_ADMIN)
187        } else {
188            Ok(false)
189        }
190    }
191
192    pub(crate) fn set_next_authority(&mut self, next_authority: &Pubkey) -> Result<()> {
193        require_keys_neq!(
194            self.next_authority,
195            *next_authority,
196            CoreError::PreconditionsAreNotMet
197        );
198        self.next_authority = *next_authority;
199        Ok(())
200    }
201
202    pub(crate) fn update_authority(&mut self) -> Result<Pubkey> {
203        require_keys_neq!(
204            self.authority,
205            self.next_authority,
206            CoreError::PreconditionsAreNotMet
207        );
208        self.authority = self.next_authority;
209        Ok(self.authority)
210    }
211
212    /// Get token map address.
213    pub fn token_map(&self) -> Option<&Pubkey> {
214        if self.token_map == Pubkey::zeroed() {
215            None
216        } else {
217            Some(&self.token_map)
218        }
219    }
220
221    /// Get amount.
222    pub fn get_amount(&self, key: &str) -> Result<&Amount> {
223        let key = AmountKey::from_str(key).map_err(|_| error!(CoreError::InvalidStoreConfigKey))?;
224        self.get_amount_by_key(key)
225            .ok_or_else(|| error!(CoreError::Unimplemented))
226    }
227
228    /// Get amount by key.
229    #[inline]
230    pub fn get_amount_by_key(&self, key: AmountKey) -> Option<&Amount> {
231        self.amount.get(&key)
232    }
233
234    /// Get amount mutably
235    pub fn get_amount_mut(&mut self, key: &str) -> Result<&mut Amount> {
236        let key = AmountKey::from_str(key).map_err(|_| error!(CoreError::InvalidStoreConfigKey))?;
237        self.amount
238            .get_mut(&key)
239            .ok_or_else(|| error!(CoreError::Unimplemented))
240    }
241
242    /// Get factor.
243    pub fn get_factor(&self, key: &str) -> Result<&Factor> {
244        let key = FactorKey::from_str(key).map_err(|_| error!(CoreError::InvalidStoreConfigKey))?;
245        self.get_factor_by_key(key)
246            .ok_or_else(|| error!(CoreError::Unimplemented))
247    }
248
249    /// Get factor by key.
250    #[inline]
251    pub fn get_factor_by_key(&self, key: FactorKey) -> Option<&Factor> {
252        self.factor.get(&key)
253    }
254
255    /// Get factor mutably
256    pub fn get_factor_mut(&mut self, key: &str) -> Result<&mut Factor> {
257        let key = FactorKey::from_str(key).map_err(|_| error!(CoreError::InvalidStoreConfigKey))?;
258        self.factor
259            .get_mut(&key)
260            .ok_or_else(|| error!(CoreError::Unimplemented))
261    }
262
263    /// Get address.
264    pub fn get_address(&self, key: &str) -> Result<&Pubkey> {
265        let key =
266            AddressKey::from_str(key).map_err(|_| error!(CoreError::InvalidStoreConfigKey))?;
267        self.get_address_by_key(key)
268            .ok_or_else(|| error!(CoreError::Unimplemented))
269    }
270
271    /// Get address by key.
272    #[inline]
273    pub fn get_address_by_key(&self, key: AddressKey) -> Option<&Pubkey> {
274        self.address.get(&key)
275    }
276
277    /// Get address mutably
278    pub fn get_address_mut(&mut self, key: &str) -> Result<&mut Pubkey> {
279        let key =
280            AddressKey::from_str(key).map_err(|_| error!(CoreError::InvalidStoreConfigKey))?;
281        self.address
282            .get_mut(&key)
283            .ok_or_else(|| error!(CoreError::Unimplemented))
284    }
285
286    /// Calculate the request expiration time.
287    pub fn request_expiration_at(&self, start: i64) -> CoreResult<i64> {
288        start
289            .checked_add_unsigned(self.amount.request_expiration)
290            .ok_or(CoreError::InvalidArgument)
291    }
292
293    /// Get claimable time window size.
294    pub fn claimable_time_window(&self) -> Result<NonZeroU64> {
295        NonZeroU64::new(self.amount.claimable_time_window)
296            .ok_or_else(|| error!(CoreError::InvalidArgument))
297    }
298
299    /// Get claimable time window index for the given timestamp.
300    pub fn claimable_time_window_index(&self, timestamp: i64) -> Result<i64> {
301        let window: i64 = self
302            .claimable_time_window()?
303            .get()
304            .try_into()
305            .map_err(|_| error!(CoreError::InvalidArgument))?;
306        Ok(timestamp / window)
307    }
308
309    /// Get claimable time key for the given timestamp.
310    pub fn claimable_time_key(&self, timestamp: i64) -> Result<[u8; 8]> {
311        let index = self.claimable_time_window_index(timestamp)?;
312        Ok(index.to_le_bytes())
313    }
314
315    /// Get holding address.
316    pub fn holding(&self) -> &Pubkey {
317        &self.address.holding
318    }
319
320    /// Set the next receiver address of the treasury.
321    pub(crate) fn set_next_receiver(&mut self, next_authority: &Pubkey) -> Result<()> {
322        self.treasury.set_next_receiver(next_authority)
323    }
324
325    /// Update receiver address to the next receiver address.
326    pub(crate) fn update_receiver(&mut self) -> Result<Pubkey> {
327        self.treasury.update_receiver()?;
328        Ok(self.receiver())
329    }
330
331    /// Validate whether fees can be claimed by this address.
332    pub fn validate_claim_fees_address(&self, address: &Pubkey) -> Result<()> {
333        require!(
334            self.treasury.is_receiver(address),
335            CoreError::PermissionDenied
336        );
337        Ok(())
338    }
339
340    /// Get the receiver address.
341    pub fn receiver(&self) -> Pubkey {
342        self.treasury.receiver
343    }
344
345    /// Get the next receiver address.
346    pub fn next_receiver(&self) -> Pubkey {
347        self.treasury.next_receiver
348    }
349
350    /// Get GT State.
351    pub fn gt(&self) -> &GtState {
352        &self.gt
353    }
354
355    /// Get GT State mutably.
356    pub(crate) fn gt_mut(&mut self) -> &mut GtState {
357        &mut self.gt
358    }
359
360    /// Get feature disabled.
361    pub fn get_feature_disabled(
362        &self,
363        domain: DomainDisabledFlag,
364        action: ActionDisabledFlag,
365    ) -> Option<bool> {
366        self.disabled_features.get_disabled(domain, action)
367    }
368
369    /// Is the given feature disabled.
370    pub fn is_feature_disabled(
371        &self,
372        domain: DomainDisabledFlag,
373        action: ActionDisabledFlag,
374    ) -> bool {
375        self.get_feature_disabled(domain, action).unwrap_or(false)
376    }
377
378    /// Validate whether the given features is enabled.
379    pub fn validate_feature_enabled(
380        &self,
381        domain: DomainDisabledFlag,
382        action: ActionDisabledFlag,
383    ) -> Result<()> {
384        if self.is_feature_disabled(domain, action) {
385            msg!("Feature `{}` is disabled", display_feature(domain, action));
386            err!(CoreError::FeatureDisabled)
387        } else {
388            Ok(())
389        }
390    }
391
392    /// Set features disabled.
393    pub(crate) fn set_feature_disabled(
394        &mut self,
395        domain: DomainDisabledFlag,
396        action: ActionDisabledFlag,
397        disabled: bool,
398    ) {
399        self.disabled_features
400            .set_disabled(domain, action, disabled)
401    }
402
403    /// Returns whether the cluster has restarted since last update.
404    pub fn has_restarted(&self) -> Result<bool> {
405        Ok(self.last_restarted_slot != LastRestartSlot::get()?.last_restart_slot)
406    }
407
408    /// Validate the cluster has not restarted.
409    pub fn validate_not_restarted(&self) -> Result<&Self> {
410        require_eq!(
411            self.last_restarted_slot,
412            LastRestartSlot::get()?.last_restart_slot,
413            CoreError::StoreOutdated
414        );
415        Ok(self)
416    }
417
418    /// Validate the cluster has not restarted for mutable reference.
419    pub fn validate_not_restarted_mut(&mut self) -> Result<&mut Self> {
420        self.validate_not_restarted()?;
421        Ok(self)
422    }
423
424    pub(crate) fn update_last_restarted_slot(&mut self, update: bool) -> Result<u64> {
425        let current = LastRestartSlot::get()?.last_restart_slot;
426        if update {
427            require_neq!(
428                self.last_restarted_slot,
429                current,
430                CoreError::PreconditionsAreNotMet
431            );
432        }
433        self.last_restarted_slot = current;
434        Ok(self.last_restarted_slot)
435    }
436
437    /// Get order fee discount factor.
438    pub fn order_fee_discount_factor(&self, rank: u8, is_referred: bool) -> Result<u128> {
439        use gmsol_model::utils::apply_factor;
440
441        let discount_factor_for_rank = self.gt().order_fee_discount_factor(rank)?;
442        if is_referred {
443            let discount_factor_for_referred = self
444                .get_factor_by_key(FactorKey::OrderFeeDiscountForReferredUser)
445                .ok_or_else(|| error!(CoreError::Unimplemented))?;
446            let complement_discount_factor_for_referred = constants::MARKET_USD_UNIT
447                .checked_sub(*discount_factor_for_referred)
448                .ok_or_else(|| error!(CoreError::Internal))?;
449
450            // 1 - (1 - A) * (1 - B) == A + B * (1 - A)
451            let discount_factor = apply_factor::<_, { constants::MARKET_DECIMALS }>(
452                &discount_factor_for_rank,
453                &complement_discount_factor_for_referred,
454            )
455            .and_then(|factor| discount_factor_for_referred.checked_add(factor))
456            .ok_or_else(|| error!(CoreError::ValueOverflow))?;
457
458            debug_assert!(discount_factor <= constants::MARKET_USD_UNIT);
459
460            Ok(discount_factor)
461        } else {
462            Ok(discount_factor_for_rank)
463        }
464    }
465}
466
467/// Store Wallet Signer.
468pub(crate) struct StoreWalletSigner {
469    store: Pubkey,
470    bump_seed: [u8; 1],
471}
472
473impl StoreWalletSigner {
474    pub(crate) fn new(store: Pubkey, bump: u8) -> Self {
475        Self {
476            store,
477            bump_seed: [bump],
478        }
479    }
480
481    pub(crate) fn signer_seeds(&self) -> [&[u8]; 3] {
482        [Store::WALLET_SEED, self.store.as_ref(), &self.bump_seed]
483    }
484}
485
486/// Treasury.
487#[account(zero_copy)]
488#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
489pub struct Treasury {
490    /// Receiver.
491    receiver: Pubkey,
492    /// Next receiver.
493    next_receiver: Pubkey,
494    #[cfg_attr(feature = "debug", debug(skip))]
495    reserved: [u8; 128],
496}
497
498#[cfg(feature = "display")]
499impl std::fmt::Display for Treasury {
500    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501        write!(f, "{{ receiver={} }}", self.receiver,)
502    }
503}
504
505impl Treasury {
506    fn init(&mut self, receiver: Pubkey) {
507        self.receiver = receiver;
508        self.next_receiver = receiver;
509    }
510
511    fn is_receiver(&self, address: &Pubkey) -> bool {
512        self.receiver == *address
513    }
514
515    fn set_next_receiver(&mut self, next_receiver: &Pubkey) -> Result<()> {
516        require_keys_neq!(
517            self.next_receiver,
518            *next_receiver,
519            CoreError::PreconditionsAreNotMet
520        );
521        self.next_receiver = *next_receiver;
522        Ok(())
523    }
524
525    fn update_receiver(&mut self) -> Result<()> {
526        require_keys_neq!(
527            self.receiver,
528            self.next_receiver,
529            CoreError::PreconditionsAreNotMet
530        );
531        self.receiver = self.next_receiver;
532        Ok(())
533    }
534}
535
536/// Amounts.
537#[zero_copy]
538#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
539pub struct Amounts {
540    pub(crate) claimable_time_window: Amount,
541    pub(crate) recent_time_window: Amount,
542    pub(crate) request_expiration: Amount,
543    pub(crate) oracle_max_age: Amount,
544    pub(crate) oracle_max_timestamp_range: Amount,
545    pub(crate) oracle_max_future_timestamp_excess: Amount,
546    pub(crate) adl_prices_max_staleness: Amount,
547    #[cfg_attr(feature = "debug", debug(skip))]
548    reserved: [Amount; 126],
549}
550
551impl Amounts {
552    fn init(&mut self) {
553        self.claimable_time_window = constants::DEFAULT_CLAIMABLE_TIME_WINDOW;
554        self.recent_time_window = constants::DEFAULT_RECENT_TIME_WINDOW;
555        self.request_expiration = constants::DEFAULT_REQUEST_EXPIRATION;
556        self.oracle_max_age = constants::DEFAULT_ORACLE_MAX_AGE;
557        self.oracle_max_timestamp_range = constants::DEFAULT_ORACLE_MAX_TIMESTAMP_RANGE;
558        self.oracle_max_future_timestamp_excess =
559            constants::DEFAULT_ORACLE_MAX_FUTURE_TIMESTAMP_EXCESS;
560        self.adl_prices_max_staleness = constants::DEFAULT_ADL_PRICES_MAX_STALENESS;
561    }
562
563    /// Get.
564    fn get(&self, key: &AmountKey) -> Option<&Amount> {
565        let value = match key {
566            AmountKey::ClaimableTimeWindow => &self.claimable_time_window,
567            AmountKey::RecentTimeWindow => &self.recent_time_window,
568            AmountKey::RequestExpiration => &self.request_expiration,
569            AmountKey::OracleMaxAge => &self.oracle_max_age,
570            AmountKey::OracleMaxTimestampRange => &self.oracle_max_timestamp_range,
571            AmountKey::OracleMaxFutureTimestampExcess => &self.oracle_max_future_timestamp_excess,
572            AmountKey::AdlPricesMaxStaleness => &self.adl_prices_max_staleness,
573            _ => return None,
574        };
575        Some(value)
576    }
577
578    /// Get mutably.
579    fn get_mut(&mut self, key: &AmountKey) -> Option<&mut Amount> {
580        let value = match key {
581            AmountKey::ClaimableTimeWindow => &mut self.claimable_time_window,
582            AmountKey::RecentTimeWindow => &mut self.recent_time_window,
583            AmountKey::RequestExpiration => &mut self.request_expiration,
584            AmountKey::OracleMaxAge => &mut self.oracle_max_age,
585            AmountKey::OracleMaxTimestampRange => &mut self.oracle_max_timestamp_range,
586            AmountKey::OracleMaxFutureTimestampExcess => {
587                &mut self.oracle_max_future_timestamp_excess
588            }
589            AmountKey::AdlPricesMaxStaleness => &mut self.adl_prices_max_staleness,
590            _ => return None,
591        };
592        Some(value)
593    }
594}
595
596/// Factors.
597#[zero_copy]
598#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
599pub struct Factors {
600    pub(crate) oracle_ref_price_deviation: Factor,
601    pub(crate) order_fee_discount_for_referred_user: Factor,
602    #[cfg_attr(feature = "debug", debug(skip))]
603    reserved: [Factor; 64],
604}
605
606impl Factors {
607    fn init(&mut self) {
608        self.oracle_ref_price_deviation = constants::DEFAULT_ORACLE_REF_PRICE_DEVIATION;
609    }
610
611    /// Get.
612    fn get(&self, key: &FactorKey) -> Option<&Factor> {
613        let value = match key {
614            FactorKey::OracleRefPriceDeviation => &self.oracle_ref_price_deviation,
615            FactorKey::OrderFeeDiscountForReferredUser => {
616                &self.order_fee_discount_for_referred_user
617            }
618            _ => return None,
619        };
620        Some(value)
621    }
622
623    /// Get mutably.
624    fn get_mut(&mut self, key: &FactorKey) -> Option<&mut Factor> {
625        let value = match key {
626            FactorKey::OracleRefPriceDeviation => &mut self.oracle_ref_price_deviation,
627            FactorKey::OrderFeeDiscountForReferredUser => {
628                &mut self.order_fee_discount_for_referred_user
629            }
630            _ => return None,
631        };
632        Some(value)
633    }
634}
635
636/// Addresses.
637#[zero_copy]
638#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
639pub struct Addresses {
640    pub(crate) holding: Pubkey,
641    #[cfg_attr(feature = "debug", debug(skip))]
642    reserved: [Pubkey; 30],
643}
644
645impl Addresses {
646    fn init(&mut self, holding: Pubkey) {
647        self.holding = holding;
648    }
649
650    /// Get.
651    fn get(&self, key: &AddressKey) -> Option<&Pubkey> {
652        let value = match key {
653            AddressKey::Holding => &self.holding,
654            _ => return None,
655        };
656        Some(value)
657    }
658
659    /// Get mutably.
660    fn get_mut(&mut self, key: &AddressKey) -> Option<&mut Pubkey> {
661        let value = match key {
662            AddressKey::Holding => &mut self.holding,
663            _ => return None,
664        };
665        Some(value)
666    }
667}