1pub use light_compressed_account::LightInstructionData;
2use light_sdk_types::constants::{CPI_AUTHORITY_PDA_SEED, LIGHT_SYSTEM_PROGRAM_ID};
3
4#[cfg(feature = "cpi-context")]
5use crate::AccountMeta;
6use crate::{
7 cpi::{account::CpiAccountsTrait, instruction::LightCpiInstruction},
8 error::LightSdkError,
9 invoke_signed, AccountInfo, Instruction, ProgramError,
10};
11
12pub trait InvokeLightSystemProgram {
13 fn invoke<'info>(self, accounts: impl CpiAccountsTrait<'info>) -> Result<(), ProgramError>;
14
15 #[cfg(feature = "cpi-context")]
16 fn invoke_write_to_cpi_context_first<'info>(
17 self,
18 accounts: impl CpiAccountsTrait<'info>,
19 ) -> Result<(), ProgramError>;
20
21 #[cfg(feature = "cpi-context")]
22 fn invoke_write_to_cpi_context_set<'info>(
23 self,
24 accounts: impl CpiAccountsTrait<'info>,
25 ) -> Result<(), ProgramError>;
26
27 #[cfg(feature = "cpi-context")]
28 fn invoke_execute_cpi_context<'info>(
29 self,
30 accounts: impl CpiAccountsTrait<'info>,
31 ) -> Result<(), ProgramError>;
32}
33
34impl<T> InvokeLightSystemProgram for T
36where
37 T: LightInstructionData + LightCpiInstruction,
38{
39 fn invoke<'info>(self, accounts: impl CpiAccountsTrait<'info>) -> Result<(), ProgramError> {
40 #[cfg(feature = "cpi-context")]
41 {
42 use light_compressed_account::instruction_data::cpi_context::CompressedCpiContext;
44 if self.get_with_cpi_context()
45 || *self.get_cpi_context() == CompressedCpiContext::set()
46 || *self.get_cpi_context() == CompressedCpiContext::first()
47 {
48 solana_msg::msg!(
49 "CPI context operations not supported in invoke(). Use invoke_write_to_cpi_context_first(), invoke_write_to_cpi_context_set(), or invoke_execute_cpi_context() instead"
50 );
51 return Err(ProgramError::InvalidInstructionData);
52 }
53 }
54
55 if let Some(account_mode) = accounts.get_mode() {
57 if account_mode != self.get_mode() {
58 solana_msg::msg!(
59 "Mode mismatch: accounts have mode {} but instruction data has mode {}",
60 account_mode,
61 self.get_mode()
62 );
63 return Err(ProgramError::InvalidInstructionData);
64 }
65 }
66
67 let data = self
69 .data()
70 .map_err(LightSdkError::from)
71 .map_err(ProgramError::from)?;
72
73 let account_infos = accounts.to_account_infos();
75 let account_metas = accounts.to_account_metas()?;
76
77 let instruction = Instruction {
78 program_id: LIGHT_SYSTEM_PROGRAM_ID.into(),
79 accounts: account_metas,
80 data,
81 };
82
83 invoke_light_system_program(&account_infos, instruction, self.get_bump())
84 }
85
86 #[cfg(feature = "cpi-context")]
87 fn invoke_write_to_cpi_context_first<'info>(
88 self,
89 accounts: impl CpiAccountsTrait<'info>,
90 ) -> Result<(), ProgramError> {
91 let instruction_data = self.write_to_cpi_context_first();
92 inner_invoke_write_to_cpi_context_typed(instruction_data, accounts)
93 }
94
95 #[cfg(feature = "cpi-context")]
96 fn invoke_write_to_cpi_context_set<'info>(
97 self,
98 accounts: impl CpiAccountsTrait<'info>,
99 ) -> Result<(), ProgramError> {
100 let instruction_data = self.write_to_cpi_context_set();
101 inner_invoke_write_to_cpi_context_typed(instruction_data, accounts)
102 }
103
104 #[cfg(feature = "cpi-context")]
105 fn invoke_execute_cpi_context<'info>(
106 self,
107 accounts: impl CpiAccountsTrait<'info>,
108 ) -> Result<(), ProgramError> {
109 let instruction_data = self.execute_with_cpi_context();
110 let data = instruction_data
112 .data()
113 .map_err(LightSdkError::from)
114 .map_err(ProgramError::from)?;
115
116 let account_infos = accounts.to_account_infos();
118 let account_metas = accounts.to_account_metas()?;
119
120 let instruction = Instruction {
121 program_id: LIGHT_SYSTEM_PROGRAM_ID.into(),
122 accounts: account_metas,
123 data,
124 };
125 invoke_light_system_program(&account_infos, instruction, instruction_data.get_bump())
126 }
127}
128
129#[cfg(feature = "cpi-context")]
131#[inline(always)]
132fn inner_invoke_write_to_cpi_context_typed<'info, T>(
133 instruction_data: T,
134 accounts: impl CpiAccountsTrait<'info>,
135) -> Result<(), ProgramError>
136where
137 T: LightInstructionData + LightCpiInstruction,
138{
139 let data = instruction_data
141 .data()
142 .map_err(LightSdkError::from)
143 .map_err(ProgramError::from)?;
144
145 let account_infos = accounts.to_account_infos();
147
148 if account_infos.len() < 3 {
151 return Err(ProgramError::NotEnoughAccountKeys);
152 }
153
154 let instruction = Instruction {
155 program_id: LIGHT_SYSTEM_PROGRAM_ID.into(),
156 accounts: vec![
157 AccountMeta {
158 pubkey: *account_infos[0].key, is_writable: true,
160 is_signer: true,
161 },
162 AccountMeta {
163 pubkey: *account_infos[1].key, is_writable: false,
165 is_signer: true,
166 },
167 AccountMeta {
168 pubkey: *account_infos[2].key, is_writable: true,
170 is_signer: false,
171 },
172 ],
173 data,
174 };
175
176 invoke_light_system_program(&account_infos, instruction, instruction_data.get_bump())
177}
178
179#[inline(always)]
185pub fn invoke_light_system_program(
186 account_infos: &[AccountInfo],
187 instruction: Instruction,
188 bump: u8,
189) -> Result<(), ProgramError> {
190 let signer_seeds = [CPI_AUTHORITY_PDA_SEED, &[bump]];
191 invoke_signed(&instruction, account_infos, &[signer_seeds.as_slice()])
192}