1use light_compressed_account::{
2 compressed_account::ReadOnlyCompressedAccount,
3 instruction_data::{
4 cpi_context::CompressedCpiContext,
5 data::{NewAddressParamsPacked, ReadOnlyAddress},
6 invoke_cpi::InstructionDataInvokeCpi,
7 with_account_info::CompressedAccountInfo,
8 },
9};
10use light_sdk_types::constants::{CPI_AUTHORITY_PDA_SEED, LIGHT_SYSTEM_PROGRAM_ID};
11
12use crate::{
13 cpi::{to_account_metas, CpiAccounts},
14 error::{LightSdkError, Result},
15 instruction::{account_info::CompressedAccountInfoTrait, ValidityProof},
16 invoke_signed, AccountInfo, AccountMeta, AnchorSerialize, Instruction,
17};
18
19#[derive(Debug, Default, PartialEq, Clone)]
20pub struct CpiInputs {
21 pub proof: ValidityProof,
22 pub account_infos: Option<Vec<CompressedAccountInfo>>,
23 pub read_only_accounts: Option<Vec<ReadOnlyCompressedAccount>>,
24 pub new_addresses: Option<Vec<NewAddressParamsPacked>>,
25 pub read_only_address: Option<Vec<ReadOnlyAddress>>,
26 pub compress_or_decompress_lamports: Option<u64>,
27 pub is_compress: bool,
28 pub cpi_context: Option<CompressedCpiContext>,
29}
30
31impl CpiInputs {
32 pub fn new(proof: ValidityProof, account_infos: Vec<CompressedAccountInfo>) -> Self {
33 Self {
34 proof,
35 account_infos: Some(account_infos),
36 ..Default::default()
37 }
38 }
39
40 pub fn new_with_address(
41 proof: ValidityProof,
42 account_infos: Vec<CompressedAccountInfo>,
43 new_addresses: Vec<NewAddressParamsPacked>,
44 ) -> Self {
45 Self {
46 proof,
47 account_infos: Some(account_infos),
48 new_addresses: Some(new_addresses),
49 ..Default::default()
50 }
51 }
52
53 pub fn invoke_light_system_program(self, cpi_accounts: CpiAccounts) -> Result<()> {
54 let bump = cpi_accounts.bump();
55 let account_info_refs = cpi_accounts.to_account_infos();
56 let instruction = create_light_system_progam_instruction_invoke_cpi(self, cpi_accounts)?;
57 let account_infos: Vec<AccountInfo> = account_info_refs.into_iter().cloned().collect();
58 invoke_light_system_program(account_infos.as_slice(), instruction, bump)
59 }
60}
61
62pub fn create_light_system_progam_instruction_invoke_cpi(
63 cpi_inputs: CpiInputs,
64 cpi_accounts: CpiAccounts,
65) -> Result<Instruction> {
66 let owner = *cpi_accounts.invoking_program()?.key;
67 let (input_compressed_accounts_with_merkle_context, output_compressed_accounts) =
68 if let Some(account_infos) = cpi_inputs.account_infos.as_ref() {
69 let mut input_compressed_accounts_with_merkle_context =
70 Vec::with_capacity(account_infos.len());
71 let mut output_compressed_accounts = Vec::with_capacity(account_infos.len());
72 for account_info in account_infos.iter() {
73 if let Some(input_account) =
74 account_info.input_compressed_account(owner.to_bytes().into())?
75 {
76 input_compressed_accounts_with_merkle_context.push(input_account);
77 }
78 if let Some(output_account) =
79 account_info.output_compressed_account(owner.to_bytes().into())?
80 {
81 output_compressed_accounts.push(output_account);
82 }
83 }
84 (
85 input_compressed_accounts_with_merkle_context,
86 output_compressed_accounts,
87 )
88 } else {
89 (vec![], vec![])
90 };
91 #[cfg(not(feature = "v2"))]
92 if cpi_inputs.read_only_accounts.is_some() {
93 unimplemented!("read_only_accounts are only supported with v2 soon on Devnet.");
94 }
95 #[cfg(not(feature = "v2"))]
96 if cpi_inputs.read_only_address.is_some() {
97 unimplemented!("read_only_addresses are only supported with v2 soon on Devnet.");
98 }
99
100 let inputs = InstructionDataInvokeCpi {
101 proof: cpi_inputs.proof.into(),
102 new_address_params: cpi_inputs.new_addresses.unwrap_or_default(),
103 relay_fee: None,
104 input_compressed_accounts_with_merkle_context,
105 output_compressed_accounts,
106 compress_or_decompress_lamports: cpi_inputs.compress_or_decompress_lamports,
107 is_compress: cpi_inputs.is_compress,
108 cpi_context: cpi_inputs.cpi_context,
109 };
110 let inputs = inputs.try_to_vec().map_err(|_| LightSdkError::Borsh)?;
111
112 let mut data = Vec::with_capacity(8 + 4 + inputs.len());
113 data.extend_from_slice(&light_compressed_account::discriminators::DISCRIMINATOR_INVOKE_CPI);
114 data.extend_from_slice(&(inputs.len() as u32).to_le_bytes());
115 data.extend(inputs);
116
117 let account_metas: Vec<AccountMeta> = to_account_metas(cpi_accounts)?;
118 Ok(Instruction {
119 program_id: LIGHT_SYSTEM_PROGRAM_ID.into(),
120 accounts: account_metas,
121 data,
122 })
123}
124
125pub fn verify_borsh<T>(light_system_accounts: CpiAccounts, inputs: &T) -> Result<()>
129where
130 T: AnchorSerialize,
131{
132 let inputs = inputs.try_to_vec().map_err(|_| LightSdkError::Borsh)?;
133
134 let mut data = Vec::with_capacity(8 + 4 + inputs.len());
135 data.extend_from_slice(&light_compressed_account::discriminators::DISCRIMINATOR_INVOKE_CPI);
136 data.extend_from_slice(&(inputs.len() as u32).to_le_bytes());
137 data.extend(inputs);
138 let account_info_refs = light_system_accounts.to_account_infos();
139 let account_infos: Vec<AccountInfo> = account_info_refs.into_iter().cloned().collect();
140
141 let bump = light_system_accounts.bump();
142 let account_metas: Vec<AccountMeta> = to_account_metas(light_system_accounts)?;
143 let instruction = Instruction {
144 program_id: LIGHT_SYSTEM_PROGRAM_ID.into(),
145 accounts: account_metas,
146 data,
147 };
148 invoke_light_system_program(account_infos.as_slice(), instruction, bump)
149}
150
151#[inline(always)]
152pub fn invoke_light_system_program(
153 account_infos: &[AccountInfo],
154 instruction: Instruction,
155 bump: u8,
156) -> Result<()> {
157 let signer_seeds = [CPI_AUTHORITY_PDA_SEED, &[bump]];
158
159 invoke_signed(&instruction, account_infos, &[signer_seeds.as_slice()])?;
177 Ok(())
178}