light_client/indexer/types/
account.rs1use light_compressed_account::{
2 compressed_account::{
3 CompressedAccount as ProgramCompressedAccount, CompressedAccountData,
4 CompressedAccountWithMerkleContext,
5 },
6 TreeType,
7};
8use solana_pubkey::Pubkey;
9use tracing::warn;
10
11use super::{
12 super::{base58::decode_base58_to_fixed_array, tree_info::QUEUE_TREE_MAPPING, IndexerError},
13 tree::{NextTreeInfo, TreeInfo},
14};
15
16#[derive(Clone, Default, Debug, PartialEq)]
17pub struct CompressedAccount {
18 pub address: Option<[u8; 32]>,
19 pub data: Option<CompressedAccountData>,
20 pub hash: [u8; 32],
21 pub lamports: u64,
22 pub leaf_index: u32,
23 pub owner: Pubkey,
24 pub prove_by_index: bool,
25 pub seq: Option<u64>,
26 pub slot_created: u64,
27 pub tree_info: TreeInfo,
28}
29
30impl TryFrom<CompressedAccountWithMerkleContext> for CompressedAccount {
31 type Error = IndexerError;
32
33 fn try_from(account: CompressedAccountWithMerkleContext) -> Result<Self, Self::Error> {
34 let hash = account
35 .hash()
36 .map_err(|e| IndexerError::decode_error("data", e))?;
37 let tree_info = QUEUE_TREE_MAPPING.get(
39 &Pubkey::new_from_array(account.merkle_context.merkle_tree_pubkey.to_bytes())
40 .to_string(),
41 );
42 let cpi_context = if let Some(tree_info) = tree_info {
43 tree_info.cpi_context
44 } else {
45 warn!("Cpi context not found in queue tree mapping");
46 None
47 };
48 Ok(CompressedAccount {
49 address: account.compressed_account.address,
50 data: account.compressed_account.data,
51 hash,
52 lamports: account.compressed_account.lamports,
53 leaf_index: account.merkle_context.leaf_index,
54 tree_info: TreeInfo {
55 tree: Pubkey::new_from_array(account.merkle_context.merkle_tree_pubkey.to_bytes()),
56 queue: Pubkey::new_from_array(account.merkle_context.queue_pubkey.to_bytes()),
57 tree_type: account.merkle_context.tree_type,
58 cpi_context,
59 next_tree_info: None,
60 },
61 owner: Pubkey::new_from_array(account.compressed_account.owner.to_bytes()),
62 prove_by_index: account.merkle_context.prove_by_index,
63 seq: None,
64 slot_created: u64::MAX,
65 })
66 }
67}
68
69impl From<CompressedAccount> for CompressedAccountWithMerkleContext {
70 fn from(account: CompressedAccount) -> Self {
71 use light_compressed_account::Pubkey;
72 let compressed_account = ProgramCompressedAccount {
73 owner: Pubkey::new_from_array(account.owner.to_bytes()),
74 lamports: account.lamports,
75 address: account.address,
76 data: account.data,
77 };
78
79 let merkle_context = account
80 .tree_info
81 .to_light_merkle_context(account.leaf_index, account.prove_by_index);
82
83 CompressedAccountWithMerkleContext {
84 compressed_account,
85 merkle_context,
86 }
87 }
88}
89
90impl TryFrom<&photon_api::types::AccountV2> for CompressedAccount {
91 type Error = IndexerError;
92
93 fn try_from(account: &photon_api::types::AccountV2) -> Result<Self, Self::Error> {
94 let data = if let Some(data) = &account.data {
95 Ok::<Option<CompressedAccountData>, IndexerError>(Some(CompressedAccountData {
96 discriminator: (*data.discriminator).to_le_bytes(),
97 data: base64::decode_config(&*data.data, base64::STANDARD_NO_PAD)
98 .map_err(|e| IndexerError::decode_error("data", e))?,
99 data_hash: decode_base58_to_fixed_array(&data.data_hash)?,
100 }))
101 } else {
102 Ok::<Option<CompressedAccountData>, IndexerError>(None)
103 }?;
104
105 let owner = Pubkey::new_from_array(decode_base58_to_fixed_array(&account.owner)?);
106 let address = account
107 .address
108 .as_ref()
109 .map(|address| decode_base58_to_fixed_array(address))
110 .transpose()?;
111 let hash = decode_base58_to_fixed_array(&account.hash)?;
112
113 let tree_info = TreeInfo {
114 tree: Pubkey::new_from_array(decode_base58_to_fixed_array(
115 &account.merkle_context.tree,
116 )?),
117 queue: Pubkey::new_from_array(decode_base58_to_fixed_array(
118 &account.merkle_context.queue,
119 )?),
120 tree_type: TreeType::from(account.merkle_context.tree_type as u64),
121 cpi_context: super::super::base58::decode_base58_option_to_pubkey(
122 &account.merkle_context.cpi_context,
123 )?,
124 next_tree_info: account
125 .merkle_context
126 .next_tree_context
127 .as_ref()
128 .map(NextTreeInfo::try_from)
129 .transpose()?,
130 };
131
132 Ok(CompressedAccount {
133 owner,
134 address,
135 data,
136 hash,
137 lamports: *account.lamports,
138 leaf_index: *account.leaf_index as u32,
139 seq: account.seq.as_ref().map(|s| **s),
140 slot_created: *account.slot_created,
141 tree_info,
142 prove_by_index: account.prove_by_index,
143 })
144 }
145}
146
147impl TryFrom<&photon_api::types::Account> for CompressedAccount {
148 type Error = IndexerError;
149
150 fn try_from(account: &photon_api::types::Account) -> Result<Self, Self::Error> {
151 let data = if let Some(data) = &account.data {
152 Ok::<Option<CompressedAccountData>, IndexerError>(Some(CompressedAccountData {
153 discriminator: (*data.discriminator).to_le_bytes(),
154 data: base64::decode_config(&*data.data, base64::STANDARD_NO_PAD)
155 .map_err(|e| IndexerError::decode_error("data", e))?,
156 data_hash: decode_base58_to_fixed_array(&data.data_hash)?,
157 }))
158 } else {
159 Ok::<Option<CompressedAccountData>, IndexerError>(None)
160 }?;
161 let owner = Pubkey::new_from_array(decode_base58_to_fixed_array(&account.owner)?);
162 let address = account
163 .address
164 .as_ref()
165 .map(|address| decode_base58_to_fixed_array(address))
166 .transpose()?;
167 let hash = decode_base58_to_fixed_array(&account.hash)?;
168 let seq = account.seq.as_ref().map(|s| **s);
169 let slot_created = *account.slot_created;
170 let lamports = *account.lamports;
171 let leaf_index = *account.leaf_index as u32;
172
173 let tree_info =
174 QUEUE_TREE_MAPPING
175 .get(&*account.tree)
176 .ok_or(IndexerError::MissingResult {
177 context: "conversion".into(),
178 message: "expected value was None".into(),
179 })?;
180
181 let tree_info = TreeInfo {
182 cpi_context: tree_info.cpi_context,
183 queue: tree_info.queue,
184 tree_type: tree_info.tree_type,
185 next_tree_info: None,
186 tree: tree_info.tree,
187 };
188
189 Ok(CompressedAccount {
190 owner,
191 address,
192 data,
193 hash,
194 lamports,
195 leaf_index,
196 seq,
197 slot_created,
198 tree_info,
199 prove_by_index: false,
200 })
201 }
202}