sealevel_tools/cpi/
mod.rs1#[cfg(feature = "alloc")]
4mod alloc;
5#[cfg(feature = "token")]
6pub mod ata_program;
7pub mod system_program;
8#[cfg(feature = "token")]
9pub mod token_program;
10
11#[cfg(feature = "alloc")]
12pub use alloc::*;
13
14pub use solana_cpi::{set_return_data, MAX_RETURN_DATA};
15
16#[cfg(feature = "alloc")]
17pub use solana_cpi::get_return_data as checked_dynamic_return_data;
18
19use core::ops::Deref;
20
21use crate::{
22 entrypoint::{AccountInfoC, AccountMetaC, InstructionC, NoStdAccountInfo, ProgramResult},
23 pubkey::Pubkey,
24};
25
26#[derive(Clone, PartialEq, Eq)]
29pub struct CpiAuthority<'a, 'b: 'a> {
30 pub account: &'b NoStdAccountInfo,
31 pub signer_seeds: Option<&'a [&'b [u8]]>,
32}
33
34impl<'a, 'b: 'a> Deref for CpiAuthority<'a, 'b> {
35 type Target = NoStdAccountInfo;
36
37 fn deref(&self) -> &Self::Target {
38 self.account
39 }
40}
41
42#[inline(always)]
47pub fn unwrap_signers_seeds<'a, 'b: 'a, const NUM_POSSIBLE: usize>(
48 possible_signers_seeds: &[Option<&'a [&'b [u8]]>; NUM_POSSIBLE],
49) -> ([&'a [&'b [u8]]; NUM_POSSIBLE], usize) {
50 let mut signers_seeds = [Default::default(); NUM_POSSIBLE];
51 let mut end = 0;
52
53 possible_signers_seeds.iter().for_each(|seeds| {
54 if let Some(seeds) = seeds {
55 signers_seeds[end] = *seeds;
56 end += 1;
57 }
58 });
59
60 (signers_seeds, end)
61}
62
63#[derive(Debug, Clone)]
66pub struct CpiInstruction<'a> {
67 pub program_id: &'a Pubkey,
68
69 pub accounts: &'a [AccountMetaC],
71 pub data: &'a [u8],
72}
73
74impl<'a> CpiInstruction<'a> {
75 #[inline(always)]
77 pub fn invoke_signed(&self, infos: &[AccountInfoC], signers_seeds: &[&[&[u8]]]) {
78 let Self {
79 program_id,
80 accounts,
81 data,
82 } = *self;
83
84 let instruction = InstructionC {
85 program_id,
86 accounts: accounts.as_ptr(),
87 accounts_len: accounts.len() as u64,
88 data: data.as_ptr(),
89 data_len: data.len() as u64,
90 };
91
92 invoke_signed_c(&instruction, infos, signers_seeds);
93 }
94
95 #[inline(always)]
98 pub fn invoke_possibly_signed<const NUM_POSSIBLE: usize>(
99 &self,
100 infos: &[AccountInfoC],
101 possible_signers_seeds: &[Option<&[&[u8]]>; NUM_POSSIBLE],
102 ) {
103 let (signers_seeds, end) = unwrap_signers_seeds(possible_signers_seeds);
104 self.invoke_signed(infos, &signers_seeds[..end]);
105 }
106
107 #[inline(always)]
110 pub fn checked_return_data<const DATA_LEN: usize>(
111 &self,
112 infos: &[AccountInfoC],
113 signers_seeds: &[&[&[u8]]],
114 ) -> Option<[u8; DATA_LEN]> {
115 self.invoke_signed(infos, signers_seeds);
116 checked_return_data::<DATA_LEN>().map(|(_, data)| data)
117 }
118
119 #[cfg(feature = "alloc")]
122 #[inline(always)]
123 pub fn checked_dynamic_return_data(
124 &self,
125 infos: &[AccountInfoC],
126 signers_seeds: &[&[&[u8]]],
127 ) -> Option<::alloc::vec::Vec<u8>> {
128 self.invoke_signed(infos, signers_seeds);
129 checked_dynamic_return_data().map(|(_, data)| data)
130 }
131}
132
133#[allow(unexpected_cfgs)]
136#[inline(always)]
137pub fn invoke_signed_c(
138 instruction: &InstructionC,
139 infos: &[AccountInfoC],
140 signers_seeds: &[&[&[u8]]],
141) {
142 #[cfg(target_os = "solana")]
143 unsafe {
144 solana_cpi::syscalls::sol_invoke_signed_c(
145 instruction as *const InstructionC as *const u8,
146 infos.as_ptr() as *const u8,
147 infos.len() as u64,
148 signers_seeds.as_ptr() as *const u8,
149 signers_seeds.len() as u64,
150 );
151 }
152
153 #[cfg(not(target_os = "solana"))]
154 let _ = (instruction, infos, signers_seeds);
155}
156
157#[inline(always)]
161pub fn try_check_borrow_account_info(account_info: &NoStdAccountInfo) -> ProgramResult {
162 if account_info.is_writable() {
163 let _ = account_info.try_borrow_mut_lamports()?;
164 let _ = account_info.try_borrow_mut_data()?;
165 } else {
166 let _ = account_info.try_borrow_lamports()?;
167 let _ = account_info.try_borrow_data()?;
168 }
169
170 Ok(())
171}
172
173#[allow(unexpected_cfgs)]
177pub fn checked_return_data<const DATA_LEN: usize>() -> Option<(Pubkey, [u8; DATA_LEN])> {
178 assert!(
179 DATA_LEN <= MAX_RETURN_DATA,
180 "Return data size exceeds 1,024 bytes"
181 );
182
183 #[cfg(target_os = "solana")]
184 {
185 let mut buf = [0; DATA_LEN];
186 let mut program_id = Pubkey::default();
187
188 let size = unsafe {
189 solana_cpi::syscalls::sol_get_return_data(
190 buf.as_mut_ptr(),
191 buf.len() as u64,
192 &mut program_id,
193 )
194 };
195
196 if size == 0 || size != (DATA_LEN as u64) {
197 None
198 } else {
199 Some((program_id, buf))
200 }
201 }
202
203 #[cfg(not(target_os = "solana"))]
204 None
205}