1use std::ops::{Deref, DerefMut};
69
70use light_compressed_account::{
71 compressed_account::PackedMerkleContext,
72 instruction_data::with_account_info::{CompressedAccountInfo, InAccountInfo, OutAccountInfo},
73};
74use light_sdk_types::instruction::account_meta::CompressedAccountMetaTrait;
75use solana_pubkey::Pubkey;
76
77use crate::{
78 error::LightSdkError,
79 light_hasher::{DataHasher, Poseidon},
80 AnchorDeserialize, AnchorSerialize, LightDiscriminator,
81};
82
83#[derive(Debug, PartialEq)]
84pub struct LightAccount<
85 'a,
86 A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + DataHasher + Default,
87> {
88 owner: &'a Pubkey,
89 pub account: A,
90 account_info: CompressedAccountInfo,
91}
92
93impl<'a, A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + DataHasher + Default>
94 LightAccount<'a, A>
95{
96 pub fn new_init(
97 owner: &'a Pubkey,
98 address: Option<[u8; 32]>,
99 output_state_tree_index: u8,
100 ) -> Self {
101 let output_account_info = OutAccountInfo {
102 output_merkle_tree_index: output_state_tree_index,
103 discriminator: A::LIGHT_DISCRIMINATOR,
104 ..Default::default()
105 };
106 Self {
107 owner,
108 account: A::default(),
109 account_info: CompressedAccountInfo {
110 address,
111 input: None,
112 output: Some(output_account_info),
113 },
114 }
115 }
116
117 pub fn new_mut(
118 owner: &'a Pubkey,
119 input_account_meta: &impl CompressedAccountMetaTrait,
120 input_account: A,
121 ) -> Result<Self, LightSdkError> {
122 let input_account_info = {
123 let input_data_hash = input_account.hash::<Poseidon>()?;
124 let tree_info = input_account_meta.get_tree_info();
125 InAccountInfo {
126 data_hash: input_data_hash,
127 lamports: input_account_meta.get_lamports().unwrap_or_default(),
128 merkle_context: PackedMerkleContext {
129 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
130 queue_pubkey_index: tree_info.queue_pubkey_index,
131 leaf_index: tree_info.leaf_index,
132 prove_by_index: tree_info.prove_by_index,
133 },
134 root_index: input_account_meta.get_root_index().unwrap_or_default(),
135 discriminator: A::LIGHT_DISCRIMINATOR,
136 }
137 };
138 let output_account_info = {
139 let output_merkle_tree_index = input_account_meta
140 .get_output_state_tree_index()
141 .ok_or(LightSdkError::OutputStateTreeIndexIsNone)?;
142 OutAccountInfo {
143 lamports: input_account_meta.get_lamports().unwrap_or_default(),
144 output_merkle_tree_index,
145 discriminator: A::LIGHT_DISCRIMINATOR,
146 ..Default::default()
147 }
148 };
149
150 Ok(Self {
151 owner,
152 account: input_account,
153 account_info: CompressedAccountInfo {
154 address: input_account_meta.get_address(),
155 input: Some(input_account_info),
156 output: Some(output_account_info),
157 },
158 })
159 }
160
161 pub fn new_close(
162 owner: &'a Pubkey,
163 input_account_meta: &impl CompressedAccountMetaTrait,
164 input_account: A,
165 ) -> Result<Self, LightSdkError> {
166 let input_account_info = {
167 let input_data_hash = input_account.hash::<Poseidon>()?;
168 let tree_info = input_account_meta.get_tree_info();
169 InAccountInfo {
170 data_hash: input_data_hash,
171 lamports: input_account_meta.get_lamports().unwrap_or_default(),
172 merkle_context: PackedMerkleContext {
173 merkle_tree_pubkey_index: tree_info.merkle_tree_pubkey_index,
174 queue_pubkey_index: tree_info.queue_pubkey_index,
175 leaf_index: tree_info.leaf_index,
176 prove_by_index: tree_info.prove_by_index,
177 },
178 root_index: input_account_meta.get_root_index().unwrap_or_default(),
179 discriminator: A::LIGHT_DISCRIMINATOR,
180 }
181 };
182 Ok(Self {
183 owner,
184 account: input_account,
185 account_info: CompressedAccountInfo {
186 address: input_account_meta.get_address(),
187 input: Some(input_account_info),
188 output: None,
189 },
190 })
191 }
192
193 pub fn discriminator(&self) -> &[u8; 8] {
194 &A::LIGHT_DISCRIMINATOR
195 }
196
197 pub fn lamports(&self) -> u64 {
198 if let Some(output) = self.account_info.output.as_ref() {
199 output.lamports
200 } else if let Some(input) = self.account_info.input.as_ref() {
201 input.lamports
202 } else {
203 0
204 }
205 }
206
207 pub fn lamports_mut(&mut self) -> &mut u64 {
208 if let Some(output) = self.account_info.output.as_mut() {
209 &mut output.lamports
210 } else if let Some(input) = self.account_info.input.as_mut() {
211 &mut input.lamports
212 } else {
213 panic!("No lamports field available in account_info")
214 }
215 }
216
217 pub fn address(&self) -> &Option<[u8; 32]> {
218 &self.account_info.address
219 }
220
221 pub fn owner(&self) -> &Pubkey {
222 self.owner
223 }
224
225 pub fn in_account_info(&self) -> &Option<InAccountInfo> {
226 &self.account_info.input
227 }
228
229 pub fn out_account_info(&mut self) -> &Option<OutAccountInfo> {
230 &self.account_info.output
231 }
232
233 pub fn to_account_info(mut self) -> Result<CompressedAccountInfo, LightSdkError> {
239 if let Some(output) = self.account_info.output.as_mut() {
240 output.data_hash = self.account.hash::<Poseidon>()?;
241 output.data = self
242 .account
243 .try_to_vec()
244 .map_err(|_| LightSdkError::Borsh)?;
245 }
246 Ok(self.account_info)
247 }
248}
249
250impl<A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + DataHasher + Default> Deref
251 for LightAccount<'_, A>
252{
253 type Target = A;
254
255 fn deref(&self) -> &Self::Target {
256 &self.account
257 }
258}
259
260impl<A: AnchorSerialize + AnchorDeserialize + LightDiscriminator + DataHasher + Default> DerefMut
261 for LightAccount<'_, A>
262{
263 fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
264 &mut self.account
265 }
266}