gmsol_programs/utils/
store.rs

1use std::num::NonZeroU64;
2
3use bytemuck::Zeroable;
4
5use crate::gmsol_store::{
6    accounts::{Glv, GtExchange, Market, Position, ReferralCodeV2, Store},
7    types::{ActionHeader, EventPositionState, Pool, PositionState},
8};
9
10/// Referral Code Bytes.
11pub type ReferralCodeBytes = [u8; 8];
12
13impl Default for Market {
14    fn default() -> Self {
15        Zeroable::zeroed()
16    }
17}
18
19impl Pool {
20    /// Returns whether the pool is a pure pool.
21    pub fn is_pure(&self) -> bool {
22        !matches!(self.is_pure, 0)
23    }
24}
25
26impl Default for Glv {
27    fn default() -> Self {
28        Zeroable::zeroed()
29    }
30}
31
32impl Default for Position {
33    fn default() -> Self {
34        Zeroable::zeroed()
35    }
36}
37
38impl AsRef<Position> for Position {
39    fn as_ref(&self) -> &Position {
40        self
41    }
42}
43
44impl Default for ActionHeader {
45    fn default() -> Self {
46        Zeroable::zeroed()
47    }
48}
49
50impl Default for GtExchange {
51    fn default() -> Self {
52        Zeroable::zeroed()
53    }
54}
55
56impl Store {
57    /// Get claimable time window size.
58    pub fn claimable_time_window(&self) -> crate::Result<NonZeroU64> {
59        NonZeroU64::new(self.amount.claimable_time_window)
60            .ok_or_else(|| crate::Error::custom("claimable time window cannot be zero"))
61    }
62
63    /// Get claimable time window index for the given timestamp.
64    pub fn claimable_time_window_index(&self, timestamp: i64) -> crate::Result<i64> {
65        let window: i64 = self
66            .claimable_time_window()?
67            .get()
68            .try_into()
69            .map_err(crate::Error::custom)?;
70        Ok(timestamp / window)
71    }
72
73    /// Get claimable time key for the given timestamp.
74    pub fn claimable_time_key(&self, timestamp: i64) -> crate::Result<[u8; 8]> {
75        let index = self.claimable_time_window_index(timestamp)?;
76        Ok(index.to_le_bytes())
77    }
78}
79
80impl ReferralCodeV2 {
81    /// The length of referral code.
82    pub const LEN: usize = std::mem::size_of::<ReferralCodeBytes>();
83
84    /// Decode the given code string to code bytes.
85    pub fn decode(code: &str) -> crate::Result<ReferralCodeBytes> {
86        if code.is_empty() {
87            return Err(crate::Error::custom("empty code is not supported"));
88        }
89        let code = bs58::decode(code)
90            .into_vec()
91            .map_err(crate::Error::custom)?;
92        if code.len() > Self::LEN {
93            return Err(crate::Error::custom("the code is too long"));
94        }
95        let padding = Self::LEN - code.len();
96        let mut code_bytes = ReferralCodeBytes::default();
97        code_bytes[padding..].copy_from_slice(&code);
98
99        Ok(code_bytes)
100    }
101
102    /// Encode the given code to code string.
103    pub fn encode(code: &ReferralCodeBytes, skip_leading_ones: bool) -> String {
104        let code = bs58::encode(code).into_string();
105        if skip_leading_ones {
106            code.trim_start_matches('1').to_owned()
107        } else {
108            code
109        }
110    }
111}
112
113impl From<EventPositionState> for PositionState {
114    fn from(event: EventPositionState) -> Self {
115        let EventPositionState {
116            trade_id,
117            increased_at,
118            updated_at_slot,
119            decreased_at,
120            size_in_tokens,
121            collateral_amount,
122            size_in_usd,
123            borrowing_factor,
124            funding_fee_amount_per_size,
125            long_token_claimable_funding_amount_per_size,
126            short_token_claimable_funding_amount_per_size,
127            reserved,
128        } = event;
129
130        Self {
131            trade_id,
132            increased_at,
133            updated_at_slot,
134            decreased_at,
135            size_in_tokens,
136            collateral_amount,
137            size_in_usd,
138            borrowing_factor,
139            funding_fee_amount_per_size,
140            long_token_claimable_funding_amount_per_size,
141            short_token_claimable_funding_amount_per_size,
142            reserved,
143        }
144    }
145}
146
147#[cfg(feature = "gmsol-model")]
148mod model {
149    use gmsol_model::ClockKind;
150
151    use crate::gmsol_store::types::Clocks;
152
153    impl Clocks {
154        /// Get clock value by [`ClockKind`].
155        pub fn get(&self, kind: ClockKind) -> Option<i64> {
156            let clock = match kind {
157                ClockKind::PriceImpactDistribution => self.price_impact_distribution,
158                ClockKind::Borrowing => self.borrowing,
159                ClockKind::Funding => self.funding,
160                ClockKind::AdlForLong => self.adl_for_long,
161                ClockKind::AdlForShort => self.adl_for_short,
162                _ => return None,
163            };
164            Some(clock)
165        }
166    }
167}
168
169#[cfg(feature = "gmsol-utils")]
170mod utils {
171    use anchor_lang::prelude::Pubkey;
172    use gmsol_utils::{
173        action::{ActionCallbackKind, ActionFlag, ActionState, MAX_ACTION_FLAGS},
174        fixed_str::bytes_to_fixed_str,
175        glv::{GlvMarketFlag, MAX_GLV_MARKET_FLAGS},
176        impl_fixed_map, impl_flags,
177        market::{self, HasMarketMeta, MarketConfigKey, MarketFlag, MAX_MARKET_FLAGS},
178        order::{self, PositionKind, TradeFlag, TradeFlagContainer},
179        pubkey::{self, optional_address},
180        swap::{self, HasSwapParams},
181        token_config::{self, TokensCollector},
182    };
183
184    use crate::gmsol_store::{
185        accounts::{Glv, Market, Position},
186        events::TradeEvent,
187        types::{
188            ActionFlagContainer, ActionHeader, GlvMarketConfig, GlvMarketFlagContainer, GlvMarkets,
189            GlvMarketsEntry, MarketConfig, MarketFlagContainer, MarketMeta, Members, MembersEntry,
190            OrderActionParams, OrderKind, RoleMap, RoleMapEntry, RoleMetadata, RoleStore,
191            SwapActionParams, TokenAndAccount, Tokens, TokensEntry, UpdateTokenConfigParams,
192        },
193    };
194
195    const MAX_TOKENS: usize = 256;
196    const MAX_ALLOWED_NUMBER_OF_MARKETS: usize = 96;
197    const MAX_ROLES: usize = 32;
198    const MAX_MEMBERS: usize = 64;
199
200    impl_fixed_map!(RoleMap, RoleMetadata, MAX_ROLES);
201
202    impl_fixed_map!(Members, Pubkey, pubkey::to_bytes, u32, MAX_MEMBERS);
203
204    impl_fixed_map!(Tokens, Pubkey, pubkey::to_bytes, u8, MAX_TOKENS);
205    impl_fixed_map!(
206        GlvMarkets,
207        Pubkey,
208        pubkey::to_bytes,
209        GlvMarketConfig,
210        MAX_ALLOWED_NUMBER_OF_MARKETS
211    );
212
213    impl_flags!(ActionFlag, MAX_ACTION_FLAGS, u8);
214    impl_flags!(MarketFlag, MAX_MARKET_FLAGS, u8);
215    impl_flags!(GlvMarketFlag, MAX_GLV_MARKET_FLAGS, u8);
216
217    impl From<SwapActionParams> for swap::SwapActionParams {
218        fn from(params: SwapActionParams) -> Self {
219            let SwapActionParams {
220                primary_length,
221                secondary_length,
222                num_tokens,
223                padding_0,
224                current_market_token,
225                paths,
226                tokens,
227            } = params;
228            Self {
229                primary_length,
230                secondary_length,
231                num_tokens,
232                padding_0,
233                current_market_token,
234                paths,
235                tokens,
236            }
237        }
238    }
239
240    impl From<MarketMeta> for market::MarketMeta {
241        fn from(meta: MarketMeta) -> Self {
242            let MarketMeta {
243                market_token_mint,
244                index_token_mint,
245                long_token_mint,
246                short_token_mint,
247            } = meta;
248            Self {
249                market_token_mint,
250                index_token_mint,
251                long_token_mint,
252                short_token_mint,
253            }
254        }
255    }
256
257    impl Market {
258        /// Get name.
259        pub fn name(&self) -> crate::Result<&str> {
260            bytes_to_fixed_str(&self.name).map_err(crate::Error::custom)
261        }
262    }
263
264    impl HasMarketMeta for Market {
265        fn market_meta(&self) -> &market::MarketMeta {
266            bytemuck::cast_ref(&self.meta)
267        }
268    }
269
270    impl MarketConfig {
271        /// Get config by [`MarketConfigKey`].
272        pub fn get(&self, key: MarketConfigKey) -> Option<&u128> {
273            let value = match key {
274                MarketConfigKey::SwapImpactExponent => &self.swap_impact_exponent,
275                MarketConfigKey::SwapImpactPositiveFactor => &self.swap_impact_positive_factor,
276                MarketConfigKey::SwapImpactNegativeFactor => &self.swap_impact_negative_factor,
277                MarketConfigKey::SwapFeeReceiverFactor => &self.swap_fee_receiver_factor,
278                MarketConfigKey::SwapFeeFactorForPositiveImpact => {
279                    &self.swap_fee_factor_for_positive_impact
280                }
281                MarketConfigKey::SwapFeeFactorForNegativeImpact => {
282                    &self.swap_fee_factor_for_negative_impact
283                }
284                MarketConfigKey::MinPositionSizeUsd => &self.min_position_size_usd,
285                MarketConfigKey::MinCollateralValue => &self.min_collateral_value,
286                MarketConfigKey::MinCollateralFactor => &self.min_collateral_factor,
287                MarketConfigKey::MinCollateralFactorForOpenInterestMultiplierForLong => {
288                    &self.min_collateral_factor_for_open_interest_multiplier_for_long
289                }
290                MarketConfigKey::MinCollateralFactorForOpenInterestMultiplierForShort => {
291                    &self.min_collateral_factor_for_open_interest_multiplier_for_short
292                }
293                MarketConfigKey::MaxPositivePositionImpactFactor => {
294                    &self.max_positive_position_impact_factor
295                }
296                MarketConfigKey::MaxNegativePositionImpactFactor => {
297                    &self.max_negative_position_impact_factor
298                }
299                MarketConfigKey::MaxPositionImpactFactorForLiquidations => {
300                    &self.max_position_impact_factor_for_liquidations
301                }
302                MarketConfigKey::PositionImpactExponent => &self.position_impact_exponent,
303                MarketConfigKey::PositionImpactPositiveFactor => {
304                    &self.position_impact_positive_factor
305                }
306                MarketConfigKey::PositionImpactNegativeFactor => {
307                    &self.position_impact_negative_factor
308                }
309                MarketConfigKey::OrderFeeReceiverFactor => &self.order_fee_receiver_factor,
310                MarketConfigKey::OrderFeeFactorForPositiveImpact => {
311                    &self.order_fee_factor_for_positive_impact
312                }
313                MarketConfigKey::OrderFeeFactorForNegativeImpact => {
314                    &self.order_fee_factor_for_negative_impact
315                }
316                MarketConfigKey::LiquidationFeeReceiverFactor => {
317                    &self.liquidation_fee_receiver_factor
318                }
319                MarketConfigKey::LiquidationFeeFactor => &self.liquidation_fee_factor,
320                MarketConfigKey::PositionImpactDistributeFactor => {
321                    &self.position_impact_distribute_factor
322                }
323                MarketConfigKey::MinPositionImpactPoolAmount => {
324                    &self.min_position_impact_pool_amount
325                }
326                MarketConfigKey::BorrowingFeeReceiverFactor => &self.borrowing_fee_receiver_factor,
327                MarketConfigKey::BorrowingFeeFactorForLong => &self.borrowing_fee_factor_for_long,
328                MarketConfigKey::BorrowingFeeFactorForShort => &self.borrowing_fee_factor_for_short,
329                MarketConfigKey::BorrowingFeeExponentForLong => {
330                    &self.borrowing_fee_exponent_for_long
331                }
332                MarketConfigKey::BorrowingFeeExponentForShort => {
333                    &self.borrowing_fee_exponent_for_short
334                }
335                MarketConfigKey::BorrowingFeeOptimalUsageFactorForLong => {
336                    &self.borrowing_fee_optimal_usage_factor_for_long
337                }
338                MarketConfigKey::BorrowingFeeOptimalUsageFactorForShort => {
339                    &self.borrowing_fee_optimal_usage_factor_for_short
340                }
341                MarketConfigKey::BorrowingFeeBaseFactorForLong => {
342                    &self.borrowing_fee_base_factor_for_long
343                }
344                MarketConfigKey::BorrowingFeeBaseFactorForShort => {
345                    &self.borrowing_fee_base_factor_for_short
346                }
347                MarketConfigKey::BorrowingFeeAboveOptimalUsageFactorForLong => {
348                    &self.borrowing_fee_above_optimal_usage_factor_for_long
349                }
350                MarketConfigKey::BorrowingFeeAboveOptimalUsageFactorForShort => {
351                    &self.borrowing_fee_above_optimal_usage_factor_for_short
352                }
353                MarketConfigKey::FundingFeeExponent => &self.funding_fee_exponent,
354                MarketConfigKey::FundingFeeFactor => &self.funding_fee_factor,
355                MarketConfigKey::FundingFeeMaxFactorPerSecond => {
356                    &self.funding_fee_max_factor_per_second
357                }
358                MarketConfigKey::FundingFeeMinFactorPerSecond => {
359                    &self.funding_fee_min_factor_per_second
360                }
361                MarketConfigKey::FundingFeeIncreaseFactorPerSecond => {
362                    &self.funding_fee_increase_factor_per_second
363                }
364                MarketConfigKey::FundingFeeDecreaseFactorPerSecond => {
365                    &self.funding_fee_decrease_factor_per_second
366                }
367                MarketConfigKey::FundingFeeThresholdForStableFunding => {
368                    &self.funding_fee_threshold_for_stable_funding
369                }
370                MarketConfigKey::FundingFeeThresholdForDecreaseFunding => {
371                    &self.funding_fee_threshold_for_decrease_funding
372                }
373                MarketConfigKey::ReserveFactor => &self.reserve_factor,
374                MarketConfigKey::OpenInterestReserveFactor => &self.open_interest_reserve_factor,
375                MarketConfigKey::MaxPnlFactorForLongDeposit => {
376                    &self.max_pnl_factor_for_long_deposit
377                }
378                MarketConfigKey::MaxPnlFactorForShortDeposit => {
379                    &self.max_pnl_factor_for_short_deposit
380                }
381                MarketConfigKey::MaxPnlFactorForLongWithdrawal => {
382                    &self.max_pnl_factor_for_long_withdrawal
383                }
384                MarketConfigKey::MaxPnlFactorForShortWithdrawal => {
385                    &self.max_pnl_factor_for_short_withdrawal
386                }
387                MarketConfigKey::MaxPnlFactorForLongTrader => &self.max_pnl_factor_for_long_trader,
388                MarketConfigKey::MaxPnlFactorForShortTrader => {
389                    &self.max_pnl_factor_for_short_trader
390                }
391                MarketConfigKey::MaxPnlFactorForLongAdl => &self.max_pnl_factor_for_long_adl,
392                MarketConfigKey::MaxPnlFactorForShortAdl => &self.max_pnl_factor_for_short_adl,
393                MarketConfigKey::MinPnlFactorAfterLongAdl => &self.min_pnl_factor_after_long_adl,
394                MarketConfigKey::MinPnlFactorAfterShortAdl => &self.min_pnl_factor_after_short_adl,
395                MarketConfigKey::MaxPoolAmountForLongToken => &self.max_pool_amount_for_long_token,
396                MarketConfigKey::MaxPoolAmountForShortToken => {
397                    &self.max_pool_amount_for_short_token
398                }
399                MarketConfigKey::MaxPoolValueForDepositForLongToken => {
400                    &self.max_pool_value_for_deposit_for_long_token
401                }
402                MarketConfigKey::MaxPoolValueForDepositForShortToken => {
403                    &self.max_pool_value_for_deposit_for_short_token
404                }
405                MarketConfigKey::MaxOpenInterestForLong => &self.max_open_interest_for_long,
406                MarketConfigKey::MaxOpenInterestForShort => &self.max_open_interest_for_short,
407                MarketConfigKey::MinTokensForFirstDeposit => &self.min_tokens_for_first_deposit,
408                _ => return None,
409            };
410            Some(value)
411        }
412    }
413
414    impl TokenAndAccount {
415        /// Get token.
416        pub fn token(&self) -> Option<Pubkey> {
417            optional_address(&self.token).copied()
418        }
419
420        /// Get account.
421        pub fn account(&self) -> Option<Pubkey> {
422            optional_address(&self.account).copied()
423        }
424
425        /// Get token and account.
426        pub fn token_and_account(&self) -> Option<(Pubkey, Pubkey)> {
427            let token = self.token()?;
428            let account = self.account()?;
429            Some((token, account))
430        }
431    }
432
433    impl From<OrderKind> for order::OrderKind {
434        fn from(value: OrderKind) -> Self {
435            match value {
436                OrderKind::Liquidation => Self::Liquidation,
437                OrderKind::AutoDeleveraging => Self::AutoDeleveraging,
438                OrderKind::MarketSwap => Self::MarketSwap,
439                OrderKind::MarketIncrease => Self::MarketIncrease,
440                OrderKind::MarketDecrease => Self::MarketDecrease,
441                OrderKind::LimitSwap => Self::LimitSwap,
442                OrderKind::LimitIncrease => Self::LimitIncrease,
443                OrderKind::LimitDecrease => Self::LimitDecrease,
444                OrderKind::StopLossDecrease => Self::StopLossDecrease,
445            }
446        }
447    }
448
449    impl TryFrom<order::OrderKind> for OrderKind {
450        type Error = crate::Error;
451
452        fn try_from(value: order::OrderKind) -> Result<Self, Self::Error> {
453            match value {
454                order::OrderKind::Liquidation => Ok(Self::Liquidation),
455                order::OrderKind::AutoDeleveraging => Ok(Self::AutoDeleveraging),
456                order::OrderKind::MarketSwap => Ok(Self::MarketSwap),
457                order::OrderKind::MarketIncrease => Ok(Self::MarketIncrease),
458                order::OrderKind::MarketDecrease => Ok(Self::MarketDecrease),
459                order::OrderKind::LimitSwap => Ok(Self::LimitSwap),
460                order::OrderKind::LimitIncrease => Ok(Self::LimitIncrease),
461                order::OrderKind::LimitDecrease => Ok(Self::LimitDecrease),
462                order::OrderKind::StopLossDecrease => Ok(Self::StopLossDecrease),
463                kind => Err(crate::Error::custom(format!(
464                    "unsupported order kind: {kind}"
465                ))),
466            }
467        }
468    }
469
470    impl OrderActionParams {
471        /// Get order side.
472        pub fn side(&self) -> crate::Result<order::OrderSide> {
473            self.side.try_into().map_err(crate::Error::custom)
474        }
475
476        /// Get order kind.
477        pub fn kind(&self) -> crate::Result<order::OrderKind> {
478            self.kind.try_into().map_err(crate::Error::custom)
479        }
480
481        /// Get position.
482        pub fn position(&self) -> Option<&Pubkey> {
483            optional_address(&self.position)
484        }
485
486        /// Get decrease position swap type.
487        #[cfg(feature = "model")]
488        pub fn decrease_position_swap_type(
489            &self,
490        ) -> crate::Result<gmsol_model::action::decrease_position::DecreasePositionSwapType>
491        {
492            let ty = self
493                .decrease_position_swap_type
494                .try_into()
495                .map_err(|_| crate::Error::custom("unknown decrease position swap type"))?;
496            Ok(ty)
497        }
498    }
499
500    impl Position {
501        /// Get position kind.
502        pub fn kind(&self) -> crate::Result<PositionKind> {
503            self.kind.try_into().map_err(crate::Error::custom)
504        }
505    }
506
507    impl Glv {
508        /// Get all market tokens.
509        pub fn market_tokens(&self) -> impl Iterator<Item = Pubkey> + '_ {
510            self.markets
511                .entries()
512                .map(|(key, _)| Pubkey::new_from_array(*key))
513        }
514
515        /// Get [`GlvMarketConfig`] for the given market.
516        pub fn market_config(&self, market_token: &Pubkey) -> Option<&GlvMarketConfig> {
517            self.markets.get(market_token)
518        }
519
520        /// Get the total number of markets.
521        pub fn num_markets(&self) -> usize {
522            self.markets.len()
523        }
524
525        /// Create a new [`TokensCollector`].
526        pub fn tokens_collector(&self, action: Option<&impl HasSwapParams>) -> TokensCollector {
527            TokensCollector::new(action, self.num_markets())
528        }
529    }
530
531    impl From<token_config::UpdateTokenConfigParams> for UpdateTokenConfigParams {
532        fn from(params: token_config::UpdateTokenConfigParams) -> Self {
533            let token_config::UpdateTokenConfigParams {
534                heartbeat_duration,
535                precision,
536                feeds,
537                timestamp_adjustments,
538                expected_provider,
539            } = params;
540            Self {
541                heartbeat_duration,
542                precision,
543                feeds,
544                timestamp_adjustments,
545                expected_provider,
546            }
547        }
548    }
549
550    impl ActionHeader {
551        /// Get action state.
552        pub fn action_state(&self) -> crate::Result<ActionState> {
553            ActionState::try_from(self.action_state)
554                .map_err(|_| crate::Error::custom("unknown action state"))
555        }
556
557        /// Get callback kind.
558        pub fn callback_kind(&self) -> crate::Result<ActionCallbackKind> {
559            ActionCallbackKind::try_from(self.callback_kind)
560                .map_err(|_| crate::Error::custom("unknown callback kind"))
561        }
562    }
563
564    impl TradeEvent {
565        /// Get trade data flag.
566        pub fn get_flag(&self, flag: TradeFlag) -> bool {
567            let map = TradeFlagContainer::from_value(self.flags);
568            map.get_flag(flag)
569        }
570
571        /// Return whether the position side is long.
572        pub fn is_long(&self) -> bool {
573            self.get_flag(TradeFlag::IsLong)
574        }
575
576        /// Return whether the collateral side is long.
577        pub fn is_collateral_long(&self) -> bool {
578            self.get_flag(TradeFlag::IsCollateralLong)
579        }
580
581        /// Create position from this event.
582        pub fn to_position(&self, meta: &impl HasMarketMeta) -> Position {
583            let mut position = Position::default();
584
585            let kind = if self.is_long() {
586                PositionKind::Long
587            } else {
588                PositionKind::Short
589            };
590
591            let collateral_token = if self.is_collateral_long() {
592                meta.market_meta().long_token_mint
593            } else {
594                meta.market_meta().short_token_mint
595            };
596
597            position.kind = kind as u8;
598            // Note: there's no need to provide a correct bump here for now.
599            position.bump = 0;
600            position.store = self.store;
601            position.owner = self.user;
602            position.market_token = self.market_token;
603            position.collateral_token = collateral_token;
604            position.state = self.after.into();
605            position
606        }
607    }
608
609    impl RoleMetadata {
610        /// A `u8` value indicates that this role is enabled.
611        pub const ROLE_ENABLED: u8 = u8::MAX;
612
613        /// Get the name of this role.
614        pub fn name(&self) -> crate::Result<&str> {
615            bytes_to_fixed_str(&self.name).map_err(crate::Error::custom)
616        }
617
618        /// Is enabled.
619        pub fn is_enabled(&self) -> bool {
620            self.enabled == Self::ROLE_ENABLED
621        }
622    }
623
624    impl RoleStore {
625        fn enabled_role_index(&self, role: &str) -> crate::Result<Option<u8>> {
626            if let Some(metadata) = self.roles.get(role) {
627                if metadata.name()? != role {
628                    return Err(crate::Error::custom("invalid role store"));
629                }
630                if !metadata.is_enabled() {
631                    return Err(crate::Error::custom("the given role is disabled"));
632                }
633                Ok(Some(metadata.index))
634            } else {
635                Ok(None)
636            }
637        }
638
639        /// Returns whether the address has the give role.
640        pub fn has_role(&self, authority: &Pubkey, role: &str) -> crate::Result<bool> {
641            use gmsol_utils::bitmaps::Bitmap;
642            type RoleBitmap = Bitmap<MAX_ROLES>;
643
644            let value = self
645                .members
646                .get(authority)
647                .ok_or_else(|| crate::Error::custom("not a member"))?;
648            let index = self
649                .enabled_role_index(role)?
650                .ok_or_else(|| crate::Error::custom("no such role"))?;
651            let bitmap = RoleBitmap::from_value(*value);
652            Ok(bitmap.get(index as usize))
653        }
654
655        /// Returns all members.
656        pub fn members(&self) -> impl Iterator<Item = Pubkey> + '_ {
657            self.members
658                .entries()
659                .map(|(key, _)| Pubkey::new_from_array(*key))
660        }
661
662        /// Returns all roles.
663        pub fn roles(&self) -> impl Iterator<Item = crate::Result<&str>> + '_ {
664            self.roles.entries().map(|(_, value)| value.name())
665        }
666    }
667}