light_client/indexer/types/
interface.rs1use light_compressed_account::TreeType;
2use light_token::compat::TokenData;
3use solana_account::Account;
4use solana_pubkey::Pubkey;
5
6use super::super::{base58::decode_base58_to_fixed_array, IndexerError};
7
8pub type SolanaAccountData = Account;
10
11#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct InterfaceTreeInfo {
14 pub tree: Pubkey,
15 pub queue: Pubkey,
16 pub tree_type: TreeType,
17 pub seq: Option<u64>,
18 pub slot_created: u64,
20}
21
22#[derive(Clone, Debug, PartialEq)]
24pub struct ColdData {
25 pub discriminator: [u8; 8],
26 pub data: Vec<u8>,
27 pub data_hash: [u8; 32],
28}
29
30#[derive(Clone, Debug, PartialEq)]
32pub struct ColdContext {
33 pub hash: [u8; 32],
34 pub leaf_index: u64,
35 pub tree_info: InterfaceTreeInfo,
36 pub data: ColdData,
37 pub address: Option<[u8; 32]>,
38 pub prove_by_index: bool,
39}
40
41fn decode_tree_info_v2(
43 merkle_ctx: &photon_api::types::MerkleContextV2,
44 seq: Option<u64>,
45 slot_created: u64,
46) -> Result<InterfaceTreeInfo, IndexerError> {
47 let tree = Pubkey::new_from_array(decode_base58_to_fixed_array(&merkle_ctx.tree)?);
48 let queue = Pubkey::new_from_array(decode_base58_to_fixed_array(&merkle_ctx.queue)?);
49 let tree_type = TreeType::from(merkle_ctx.tree_type as u64);
50 Ok(InterfaceTreeInfo {
51 tree,
52 queue,
53 tree_type,
54 seq,
55 slot_created,
56 })
57}
58
59fn decode_account_data(data: &photon_api::types::AccountData) -> Result<ColdData, IndexerError> {
61 let disc_val = *data.discriminator;
62 let discriminator = disc_val.to_le_bytes();
63 Ok(ColdData {
64 discriminator,
65 data: base64::decode_config(&*data.data, base64::STANDARD_NO_PAD)
66 .map_err(|e| IndexerError::decode_error("data", e))?,
67 data_hash: decode_base58_to_fixed_array(&data.data_hash)?,
68 })
69}
70
71fn convert_account_v2(av2: &photon_api::types::AccountV2) -> Result<ColdContext, IndexerError> {
73 let tree_info = decode_tree_info_v2(
74 &av2.merkle_context,
75 av2.seq.as_ref().map(|s| **s),
76 *av2.slot_created,
77 )?;
78
79 let data = match &av2.data {
80 Some(d) => decode_account_data(d)?,
81 None => ColdData {
82 discriminator: [0u8; 8],
83 data: Vec::new(),
84 data_hash: [0u8; 32],
85 },
86 };
87
88 let address = av2
89 .address
90 .as_ref()
91 .map(|a| decode_base58_to_fixed_array(a))
92 .transpose()?;
93
94 Ok(ColdContext {
95 hash: decode_base58_to_fixed_array(&av2.hash)?,
96 leaf_index: *av2.leaf_index,
97 tree_info,
98 data,
99 address,
100 prove_by_index: av2.prove_by_index,
101 })
102}
103
104#[derive(Clone, Debug, PartialEq)]
106pub struct AccountInterface {
107 pub key: Pubkey,
109 pub account: SolanaAccountData,
111 pub cold: Option<ColdContext>,
113}
114
115impl AccountInterface {
116 pub fn is_hot(&self) -> bool {
118 self.cold.is_none()
119 }
120
121 pub fn is_cold(&self) -> bool {
123 self.cold.is_some()
124 }
125}
126
127fn convert_account_interface(
129 ai: &photon_api::types::AccountInterface,
130) -> Result<AccountInterface, IndexerError> {
131 let cold = ai
133 .cold
134 .as_ref()
135 .and_then(|entries| entries.first())
136 .map(convert_account_v2)
137 .transpose()?;
138
139 let data = base64::decode_config(&*ai.account.data, base64::STANDARD_NO_PAD)
140 .map_err(|e| IndexerError::decode_error("account.data", e))?;
141
142 Ok(AccountInterface {
143 key: Pubkey::new_from_array(decode_base58_to_fixed_array(&ai.key)?),
144 account: Account {
145 lamports: *ai.account.lamports,
146 data,
147 owner: Pubkey::new_from_array(decode_base58_to_fixed_array(&ai.account.owner)?),
148 executable: ai.account.executable,
149 rent_epoch: *ai.account.rent_epoch,
150 },
151 cold,
152 })
153}
154
155impl TryFrom<&photon_api::types::AccountInterface> for AccountInterface {
156 type Error = IndexerError;
157
158 fn try_from(ai: &photon_api::types::AccountInterface) -> Result<Self, Self::Error> {
159 convert_account_interface(ai)
160 }
161}
162
163#[derive(Clone, Debug, PartialEq)]
165pub struct TokenAccountInterface {
166 pub account: AccountInterface,
168 pub token: TokenData,
170}