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#[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 pub authority: Pubkey,
32 pub(crate) next_authority: Pubkey,
34 pub token_map: Pubkey,
36 disabled_features: DisabledFeatures,
38 #[cfg_attr(feature = "debug", debug(skip))]
39 padding_1: [u8; 4],
40 last_restarted_slot: u64,
42 treasury: Treasury,
44 pub(crate) amount: Amounts,
46 #[cfg_attr(feature = "debug", debug(skip))]
47 padding_2: [u8; 8],
48 pub(crate) factor: Factors,
50 pub(crate) address: Addresses,
52 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 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 pub const MAX_LEN: usize = MAX_LEN;
92
93 pub const WALLET_SEED: &'static [u8] = b"store_wallet";
95
96 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 pub fn role(&self) -> &RoleStore {
126 &self.role
127 }
128
129 pub fn key(&self) -> Result<&str> {
131 crate::utils::fixed_str::bytes_to_fixed_str(&self.key)
132 }
133
134 pub fn enable_role(&mut self, role: &str) -> Result<()> {
136 self.role.enable_role(role)
137 }
138
139 pub fn disable_role(&mut self, role: &str) -> Result<()> {
141 self.role.disable_role(role)
142 }
143
144 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 pub fn grant(&mut self, authority: &Pubkey, role: &str) -> Result<()> {
164 self.role.grant(authority, role)
165 }
166
167 pub fn revoke(&mut self, authority: &Pubkey, role: &str) -> Result<()> {
169 self.role.revoke(authority, role)
170 }
171
172 pub fn is_authority(&self, authority: &Pubkey) -> bool {
174 self.authority == *authority
175 }
176
177 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 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 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 #[inline]
230 pub fn get_amount_by_key(&self, key: AmountKey) -> Option<&Amount> {
231 self.amount.get(&key)
232 }
233
234 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 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 #[inline]
251 pub fn get_factor_by_key(&self, key: FactorKey) -> Option<&Factor> {
252 self.factor.get(&key)
253 }
254
255 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 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 #[inline]
273 pub fn get_address_by_key(&self, key: AddressKey) -> Option<&Pubkey> {
274 self.address.get(&key)
275 }
276
277 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 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 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 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 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 pub fn holding(&self) -> &Pubkey {
317 &self.address.holding
318 }
319
320 pub(crate) fn set_next_receiver(&mut self, next_authority: &Pubkey) -> Result<()> {
322 self.treasury.set_next_receiver(next_authority)
323 }
324
325 pub(crate) fn update_receiver(&mut self) -> Result<Pubkey> {
327 self.treasury.update_receiver()?;
328 Ok(self.receiver())
329 }
330
331 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 pub fn receiver(&self) -> Pubkey {
342 self.treasury.receiver
343 }
344
345 pub fn next_receiver(&self) -> Pubkey {
347 self.treasury.next_receiver
348 }
349
350 pub fn gt(&self) -> &GtState {
352 &self.gt
353 }
354
355 pub(crate) fn gt_mut(&mut self) -> &mut GtState {
357 &mut self.gt
358 }
359
360 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 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 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 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 pub fn has_restarted(&self) -> Result<bool> {
405 Ok(self.last_restarted_slot != LastRestartSlot::get()?.last_restart_slot)
406 }
407
408 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 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 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 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
467pub(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#[account(zero_copy)]
488#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
489pub struct Treasury {
490 receiver: Pubkey,
492 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#[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 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 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#[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 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 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#[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 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 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}