pinocchio_token/instructions/
sync_native.rs1use {
2 crate::{
3 instructions::{account_borrow_failed_error, invalid_argument_error, CpiWriter},
4 UNINIT_BYTE, UNINIT_CPI_ACCOUNT, UNINIT_INSTRUCTION_ACCOUNT,
5 },
6 core::{mem::MaybeUninit, slice::from_raw_parts},
7 solana_account_view::AccountView,
8 solana_instruction_view::{
9 cpi::{invoke_unchecked, CpiAccount},
10 InstructionAccount, InstructionView,
11 },
12 solana_program_error::{ProgramError, ProgramResult},
13};
14
15pub struct SyncNative<'account> {
32 pub native_token: &'account AccountView,
34
35 pub rent_sysvar: Option<&'account AccountView>,
36}
37
38impl<'account> SyncNative<'account> {
39 pub const DISCRIMINATOR: u8 = 17;
40
41 pub const MAX_ACCOUNTS_LEN: usize = 2;
47
48 pub const DATA_LEN: usize = 1;
51
52 #[inline(always)]
53 pub fn new(
54 native_token: &'account AccountView,
55 rent_sysvar: Option<&'account AccountView>,
56 ) -> Self {
57 Self {
58 native_token,
59 rent_sysvar,
60 }
61 }
62
63 #[inline(always)]
64 pub fn invoke(&self) -> ProgramResult {
65 let mut instruction_accounts = [UNINIT_INSTRUCTION_ACCOUNT; SyncNative::MAX_ACCOUNTS_LEN];
66 let written_instruction_accounts =
67 self.write_instruction_accounts(&mut instruction_accounts)?;
68
69 let mut accounts = [UNINIT_CPI_ACCOUNT; Self::MAX_ACCOUNTS_LEN];
70 let written_accounts = self.write_accounts(&mut accounts)?;
71
72 let mut instruction_data = [UNINIT_BYTE; Self::DATA_LEN];
73 let written_instruction_data = self.write_instruction_data(&mut instruction_data)?;
74
75 unsafe {
76 invoke_unchecked(
77 &InstructionView {
78 program_id: &crate::ID,
79 accounts: from_raw_parts(
80 instruction_accounts.as_ptr() as _,
81 written_instruction_accounts,
82 ),
83 data: from_raw_parts(instruction_data.as_ptr() as _, written_instruction_data),
84 },
85 from_raw_parts(accounts.as_ptr() as _, written_accounts),
86 );
87 }
88
89 Ok(())
90 }
91}
92
93impl CpiWriter for SyncNative<'_> {
94 #[inline(always)]
95 fn write_accounts<'cpi>(
96 &self,
97 accounts: &mut [MaybeUninit<CpiAccount<'cpi>>],
98 ) -> Result<usize, ProgramError>
99 where
100 Self: 'cpi,
101 {
102 write_accounts(self.native_token, self.rent_sysvar, accounts)
103 }
104
105 #[inline(always)]
106 fn write_instruction_accounts<'cpi>(
107 &self,
108 accounts: &mut [MaybeUninit<InstructionAccount<'cpi>>],
109 ) -> Result<usize, ProgramError>
110 where
111 Self: 'cpi,
112 {
113 write_instruction_accounts(self.native_token, self.rent_sysvar, accounts)
114 }
115
116 #[inline(always)]
117 fn write_instruction_data(&self, data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
118 write_instruction_data(data)
119 }
120}
121
122impl super::IntoBatch for SyncNative<'_> {
123 #[inline(always)]
124 fn into_batch<'account, 'state>(
125 self,
126 batch: &mut super::Batch<'account, 'state>,
127 ) -> ProgramResult
128 where
129 Self: 'account + 'state,
130 {
131 batch.push(
132 |accounts| write_accounts(self.native_token, self.rent_sysvar, accounts),
133 |accounts| write_instruction_accounts(self.native_token, self.rent_sysvar, accounts),
134 write_instruction_data,
135 )
136 }
137}
138
139#[inline(always)]
140fn write_accounts<'account, 'out>(
141 native_token: &'account AccountView,
142 rent_sysvar: Option<&'account AccountView>,
143 accounts: &mut [MaybeUninit<CpiAccount<'out>>],
144) -> Result<usize, ProgramError>
145where
146 'account: 'out,
147{
148 if accounts.len() < SyncNative::MAX_ACCOUNTS_LEN {
149 return Err(invalid_argument_error());
150 }
151
152 if native_token.is_borrowed() {
153 return Err(account_borrow_failed_error());
154 }
155
156 CpiAccount::init_from_account_view(native_token, &mut accounts[0]);
157
158 if let Some(rent_sysvar) = rent_sysvar {
159 CpiAccount::init_from_account_view(rent_sysvar, &mut accounts[1]);
160 Ok(SyncNative::MAX_ACCOUNTS_LEN)
161 } else {
162 Ok(1)
163 }
164}
165
166#[inline(always)]
167fn write_instruction_accounts<'account, 'out>(
168 native_token: &'account AccountView,
169 rent_sysvar: Option<&'account AccountView>,
170 accounts: &mut [MaybeUninit<InstructionAccount<'out>>],
171) -> Result<usize, ProgramError>
172where
173 'account: 'out,
174{
175 if accounts.len() < SyncNative::MAX_ACCOUNTS_LEN {
176 return Err(invalid_argument_error());
177 }
178
179 accounts[0].write(InstructionAccount::writable(native_token.address()));
180
181 if let Some(rent_sysvar) = rent_sysvar {
182 accounts[1].write(InstructionAccount::readonly(rent_sysvar.address()));
183 Ok(SyncNative::MAX_ACCOUNTS_LEN)
184 } else {
185 Ok(1)
186 }
187}
188
189#[inline(always)]
190fn write_instruction_data(data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
191 if data.len() < SyncNative::DATA_LEN {
192 return Err(invalid_argument_error());
193 }
194
195 data[0].write(SyncNative::DISCRIMINATOR);
196
197 Ok(SyncNative::DATA_LEN)
198}