carbon_moonshot_decoder/accounts/
mod.rs

1use {
2    super::MoonshotDecoder,
3    crate::PROGRAM_ID,
4    carbon_core::{account::AccountDecoder, deserialize::CarbonDeserialize},
5};
6pub mod config_account;
7pub mod curve_account;
8
9pub enum MoonshotAccount {
10    ConfigAccount(config_account::ConfigAccount),
11    CurveAccount(curve_account::CurveAccount),
12}
13
14impl AccountDecoder<'_> for MoonshotDecoder {
15    type AccountType = MoonshotAccount;
16    fn decode_account(
17        &self,
18        account: &solana_account::Account,
19    ) -> Option<carbon_core::account::DecodedAccount<Self::AccountType>> {
20        if !account.owner.eq(&PROGRAM_ID) {
21            return None;
22        }
23
24        if let Some(decoded_account) =
25            config_account::ConfigAccount::deserialize(account.data.as_slice())
26        {
27            return Some(carbon_core::account::DecodedAccount {
28                lamports: account.lamports,
29                data: MoonshotAccount::ConfigAccount(decoded_account),
30                owner: account.owner,
31                executable: account.executable,
32                rent_epoch: account.rent_epoch,
33            });
34        }
35
36        if let Some(decoded_account) =
37            curve_account::CurveAccount::deserialize(account.data.as_slice())
38        {
39            return Some(carbon_core::account::DecodedAccount {
40                lamports: account.lamports,
41                data: MoonshotAccount::CurveAccount(decoded_account),
42                owner: account.owner,
43                executable: account.executable,
44                rent_epoch: account.rent_epoch,
45            });
46        }
47
48        None
49    }
50}
51
52#[cfg(test)]
53mod tests {
54
55    use super::*;
56
57    #[test]
58    fn test_decode_config_account() {
59        // Arrange
60        let expected_cfg_account = config_account::ConfigAccount {
61            migration_authority: solana_pubkey::Pubkey::from_str_const(
62                "CGsqR7CTqTwbmAUTPnfg9Bj9GLJgkrUD9rhjh3vHEYvh",
63            ),
64            backend_authority: solana_pubkey::Pubkey::from_str_const(
65                "Cb8Fnhp95f9dLxB3sYkNCbN3Mjxuc3v2uQZ7uVeqvNGB",
66            ),
67            config_authority: solana_pubkey::Pubkey::from_str_const(
68                "AnHuyURVXM9nzWYGJZCxBFT5MJGr9fGjTg2kKFZBHgUk",
69            ),
70            helio_fee: solana_pubkey::Pubkey::from_str_const(
71                "5K5RtTWzzLp4P8Npi84ocf7F1vBsAu29N1irG4iiUnzt",
72            ),
73            dex_fee: solana_pubkey::Pubkey::from_str_const(
74                "3udvfL24waJcLhskRAsStNMoNUvtyXdxrWQz4hgi953N",
75            ),
76            fee_bps: 100,
77            dex_fee_share: 60,
78            migration_fee: 2,
79            marketcap_threshold: 345000000000,
80            marketcap_currency: crate::types::Currency::Sol,
81            min_supported_decimal_places: 6,
82            max_supported_decimal_places: 9,
83            min_supported_token_supply: 10000000,
84            max_supported_token_supply: 1000000000,
85            bump: 251,
86            coef_b: 25,
87            ..config_account::ConfigAccount::default()
88        };
89
90        // Act
91        let decoder = MoonshotDecoder;
92        let account = carbon_test_utils::read_account("tests/fixtures/config_account.json")
93            .expect("read fixture");
94        let decoded_account = decoder.decode_account(&account).expect("decode fixture");
95
96        // Assert
97        match decoded_account.data {
98            MoonshotAccount::ConfigAccount(cfg_account) => {
99                assert_eq!(
100                    expected_cfg_account.migration_authority,
101                    cfg_account.migration_authority
102                );
103                assert_eq!(
104                    expected_cfg_account.backend_authority,
105                    cfg_account.backend_authority
106                );
107                assert_eq!(
108                    expected_cfg_account.config_authority,
109                    cfg_account.config_authority
110                );
111                assert_eq!(expected_cfg_account.helio_fee, cfg_account.helio_fee);
112                assert_eq!(expected_cfg_account.dex_fee, cfg_account.dex_fee);
113                assert_eq!(expected_cfg_account.fee_bps, cfg_account.fee_bps);
114                assert_eq!(
115                    expected_cfg_account.dex_fee_share,
116                    cfg_account.dex_fee_share
117                );
118                assert_eq!(
119                    expected_cfg_account.migration_fee,
120                    cfg_account.migration_fee
121                );
122                assert_eq!(
123                    expected_cfg_account.marketcap_threshold,
124                    cfg_account.marketcap_threshold
125                );
126                assert_eq!(
127                    expected_cfg_account.marketcap_currency,
128                    cfg_account.marketcap_currency
129                );
130                assert_eq!(
131                    expected_cfg_account.min_supported_decimal_places,
132                    cfg_account.min_supported_decimal_places
133                );
134                assert_eq!(
135                    expected_cfg_account.max_supported_decimal_places,
136                    cfg_account.max_supported_decimal_places
137                );
138                assert_eq!(
139                    expected_cfg_account.min_supported_token_supply,
140                    cfg_account.min_supported_token_supply
141                );
142                assert_eq!(
143                    expected_cfg_account.max_supported_token_supply,
144                    cfg_account.max_supported_token_supply
145                );
146                assert_eq!(expected_cfg_account.bump, cfg_account.bump);
147                assert_eq!(expected_cfg_account.coef_b, cfg_account.coef_b);
148            }
149            _ => panic!("Expected ConfigAccount"),
150        }
151    }
152
153    #[test]
154    fn test_decode_curve_account() {
155        // Arrange
156        let expected_curve_account = curve_account::CurveAccount {
157            total_supply: 1000000000000000000,
158            curve_amount: 979053197346106125,
159            mint: solana_pubkey::Pubkey::from_str_const(
160                "3cBFsM1wosTJi9yun6kcHhYHyJcut1MNQY28zjC4moon",
161            ),
162            decimals: 9,
163            collateral_currency: crate::types::Currency::Sol,
164            curve_type: crate::types::CurveType::ConstantProductV1,
165            marketcap_threshold: 345000000000,
166            marketcap_currency: crate::types::Currency::Sol,
167            migration_fee: 2,
168            coef_b: 25,
169            bump: 255,
170            migration_target: crate::types::MigrationTarget::Raydium,
171            ..curve_account::CurveAccount::default()
172        };
173
174        // Act
175        let decoder = MoonshotDecoder;
176        let account = carbon_test_utils::read_account("tests/fixtures/curve_account.json")
177            .expect("read fixture");
178        let decoded_account = decoder.decode_account(&account).expect("decode fixture");
179
180        // Assert
181        match decoded_account.data {
182            MoonshotAccount::CurveAccount(curve_account) => {
183                assert_eq!(expected_curve_account, curve_account);
184            }
185            _ => panic!("Expected CurveAccount"),
186        }
187    }
188}