tensor_eigen/commands/
decode.rs

1use borsh::BorshDeserialize;
2use tensor_amm::accounts::{NftDepositReceipt, Pool};
3use tensor_marketplace::accounts::{BidState, ListState};
4use tensor_price_lock::accounts::OrderState;
5use tensor_whitelist::accounts::{MintProof, MintProofV2, Whitelist, WhitelistV2};
6
7use crate::{
8    discriminators::deserialize_account,
9    formatting::{AccountEntry, CustomFormat},
10    types::{
11        raydium_clmm::{PoolState as ClmmPoolState, RAYDIUM_CLMM_PROGRAM_ID},
12        raydium_cp::{PoolState as CpPoolState, RAYDIUM_CPSWAP_PROGRAM_ID},
13        raydium_v4::{AmmInfo, RAYDIUM_AMM_PROGRAM_ID},
14    },
15    Shard, FEE_SHARDS,
16};
17
18use super::*;
19
20pub struct DecodeParams {
21    pub rpc_url: Option<String>,
22    pub address: Pubkey,
23    pub raw: bool,
24}
25
26pub fn handle_decode(args: DecodeParams) -> Result<()> {
27    let config = CliConfig::new(None, args.rpc_url)?;
28
29    // For `AccountNotFound` error, treat it as an unitialized system program owned wallet with 0 lamports
30    // the same way explorers do.
31    let account = match config.client.get_account(&args.address) {
32        Ok(account) => account,
33        Err(e) => {
34            // Check if error message contains "AccountNotFound"
35            if e.to_string().contains("AccountNotFound") {
36                Account {
37                    lamports: 0,
38                    data: vec![],
39                    owner: solana_sdk::system_program::ID,
40                    executable: false,
41                    rent_epoch: 0,
42                }
43            } else {
44                return Err(e.into());
45            }
46        }
47    };
48
49    if args.raw {
50        println!("{:?}", account.data);
51        return Ok(());
52    }
53
54    if is_fee_shard(&args.address.to_string()) {
55        println!(
56            "{}",
57            Shard {
58                address: args.address,
59                account
60            }
61            .custom_format()
62        );
63        return Ok(());
64    }
65
66    if is_wallet_type(&account) {
67        let account_entry = AccountEntry {
68            address: args.address,
69            account,
70        };
71        println!("{}", account_entry.custom_format());
72        return Ok(());
73    }
74
75    let mut data = account.data.as_slice();
76
77    if data.len() < 8 {
78        return Err(anyhow!("No account discriminator found!"));
79    }
80    let discriminator = &data[0..8];
81
82    match discriminator {
83        d if d == Pool::discriminator() => {
84            let pool = deserialize_account::<Pool>(data)?;
85            println!("{}", pool.custom_format());
86        }
87        d if d == NftDepositReceipt::discriminator() => {
88            let nft_deposit_receipt = deserialize_account::<NftDepositReceipt>(data)?;
89            println!("{}", nft_deposit_receipt.custom_format());
90        }
91        d if d == Whitelist::discriminator() => {
92            let whitelist = deserialize_account::<Whitelist>(data)?;
93            println!("{}", whitelist.custom_format());
94        }
95        d if d == WhitelistV2::discriminator() => {
96            let whitelist = deserialize_account::<WhitelistV2>(data)?;
97            println!("{}", whitelist.custom_format());
98        }
99        d if d == MintProof::discriminator() => {
100            let mint_proof = deserialize_account::<MintProof>(data)?;
101            println!("{}", mint_proof.custom_format());
102        }
103        d if d == MintProofV2::discriminator() => {
104            let mint_proof = deserialize_account::<MintProofV2>(data)?;
105            println!("{}", mint_proof.custom_format());
106        }
107        d if d == BidState::discriminator() => {
108            let bid_state = deserialize_account::<BidState>(data)?;
109            println!("{}", bid_state.custom_format());
110        }
111        d if d == ListState::discriminator() => {
112            let list_state = deserialize_account::<ListState>(data)?;
113            println!("{}", list_state.custom_format());
114        }
115        d if d == OrderState::discriminator() => {
116            let order_state = deserialize_account::<OrderState>(data)?;
117            println!("{}", order_state.custom_format());
118        }
119        _ => match account.owner {
120            o if o == RAYDIUM_AMM_PROGRAM_ID && data.len() == size_of::<AmmInfo>() => {
121                let amm_info = AmmInfo::deserialize(&mut data)?;
122                println!("{}", amm_info.custom_format());
123            }
124            o if o == RAYDIUM_CLMM_PROGRAM_ID => {
125                // let clmm_info = ClmmPoolState::deserialize(&mut data)?;
126                let clmm_info = deserialize_account::<ClmmPoolState>(data)?;
127                println!("{}", clmm_info.custom_format());
128            }
129            o if o == RAYDIUM_CPSWAP_PROGRAM_ID => {
130                // let cpswap_info = CpPoolState::deserialize(&mut data)?;
131                let cpswap_info = deserialize_account::<CpPoolState>(data)?;
132                println!("{}", cpswap_info.custom_format());
133            }
134            o if TOKEN_PROGRAM_IDS.contains(&o) => {
135                println!("Token or mint account");
136                println!("Data length: {}", data.len());
137                println!("Lamports: {}", account.lamports);
138                println!("Account owned by program: {}", account.owner);
139            }
140            _ => {
141                println!("Unknown account type");
142            }
143        },
144    }
145    Ok(())
146}
147
148fn is_wallet_type(account: &Account) -> bool {
149    account.owner == solana_sdk::system_program::id()
150        && account.data.is_empty()
151        && !account.executable
152}
153
154fn is_fee_shard(address: &str) -> bool {
155    FEE_SHARDS.contains(&address)
156}