pinocchio_token/instructions/
initialize_account.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 InitializeAccount<'account> {
34 pub account: &'account AccountView,
36
37 pub mint: &'account AccountView,
39
40 pub owner: &'account AccountView,
42
43 pub rent_sysvar: &'account AccountView,
45}
46
47impl<'account> InitializeAccount<'account> {
48 pub const DISCRIMINATOR: u8 = 1;
49
50 pub const ACCOUNTS_LEN: usize = 4;
52
53 pub const DATA_LEN: usize = 1;
56
57 #[inline(always)]
58 pub fn new(
59 account: &'account AccountView,
60 mint: &'account AccountView,
61 owner: &'account AccountView,
62 rent_sysvar: &'account AccountView,
63 ) -> Self {
64 Self {
65 account,
66 mint,
67 owner,
68 rent_sysvar,
69 }
70 }
71
72 #[inline(always)]
73 pub fn invoke(&self) -> ProgramResult {
74 let mut instruction_accounts =
75 [UNINIT_INSTRUCTION_ACCOUNT; InitializeAccount::ACCOUNTS_LEN];
76 let written_instruction_accounts =
77 self.write_instruction_accounts(&mut instruction_accounts)?;
78
79 let mut accounts = [UNINIT_CPI_ACCOUNT; Self::ACCOUNTS_LEN];
80 let written_accounts = self.write_accounts(&mut accounts)?;
81
82 let mut instruction_data = [UNINIT_BYTE; Self::DATA_LEN];
83 let written_instruction_data = self.write_instruction_data(&mut instruction_data)?;
84
85 unsafe {
86 invoke_unchecked(
87 &InstructionView {
88 program_id: &crate::ID,
89 accounts: from_raw_parts(
90 instruction_accounts.as_ptr() as _,
91 written_instruction_accounts,
92 ),
93 data: from_raw_parts(instruction_data.as_ptr() as _, written_instruction_data),
94 },
95 from_raw_parts(accounts.as_ptr() as _, written_accounts),
96 );
97 }
98
99 Ok(())
100 }
101}
102
103impl CpiWriter for InitializeAccount<'_> {
104 #[inline(always)]
105 fn write_accounts<'cpi>(
106 &self,
107 accounts: &mut [MaybeUninit<CpiAccount<'cpi>>],
108 ) -> Result<usize, ProgramError>
109 where
110 Self: 'cpi,
111 {
112 write_accounts(
113 self.account,
114 self.mint,
115 self.owner,
116 self.rent_sysvar,
117 accounts,
118 )
119 }
120
121 #[inline(always)]
122 fn write_instruction_accounts<'cpi>(
123 &self,
124 accounts: &mut [MaybeUninit<InstructionAccount<'cpi>>],
125 ) -> Result<usize, ProgramError>
126 where
127 Self: 'cpi,
128 {
129 write_instruction_accounts(
130 self.account,
131 self.mint,
132 self.owner,
133 self.rent_sysvar,
134 accounts,
135 )
136 }
137
138 #[inline(always)]
139 fn write_instruction_data(&self, data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
140 write_instruction_data(data)
141 }
142}
143
144impl super::IntoBatch for InitializeAccount<'_> {
145 #[inline(always)]
146 fn into_batch<'account, 'state>(
147 self,
148 batch: &mut super::Batch<'account, 'state>,
149 ) -> ProgramResult
150 where
151 Self: 'account + 'state,
152 {
153 batch.push(
154 |accounts| {
155 write_accounts(
156 self.account,
157 self.mint,
158 self.owner,
159 self.rent_sysvar,
160 accounts,
161 )
162 },
163 |accounts| {
164 write_instruction_accounts(
165 self.account,
166 self.mint,
167 self.owner,
168 self.rent_sysvar,
169 accounts,
170 )
171 },
172 write_instruction_data,
173 )
174 }
175}
176
177#[inline(always)]
178fn write_accounts<'account, 'out>(
179 account: &'account AccountView,
180 mint: &'account AccountView,
181 owner: &'account AccountView,
182 rent_sysvar: &'account AccountView,
183 accounts: &mut [MaybeUninit<CpiAccount<'out>>],
184) -> Result<usize, ProgramError>
185where
186 'account: 'out,
187{
188 if accounts.len() < InitializeAccount::ACCOUNTS_LEN {
189 return Err(invalid_argument_error());
190 }
191
192 if account.is_borrowed() {
193 return Err(account_borrow_failed_error());
194 }
195
196 CpiAccount::init_from_account_view(account, &mut accounts[0]);
197
198 CpiAccount::init_from_account_view(mint, &mut accounts[1]);
199
200 CpiAccount::init_from_account_view(owner, &mut accounts[2]);
201
202 CpiAccount::init_from_account_view(rent_sysvar, &mut accounts[3]);
203
204 Ok(InitializeAccount::ACCOUNTS_LEN)
205}
206
207#[inline(always)]
208fn write_instruction_accounts<'account, 'out>(
209 account: &'account AccountView,
210 mint: &'account AccountView,
211 owner: &'account AccountView,
212 rent_sysvar: &'account AccountView,
213 accounts: &mut [MaybeUninit<InstructionAccount<'out>>],
214) -> Result<usize, ProgramError>
215where
216 'account: 'out,
217{
218 if accounts.len() < InitializeAccount::ACCOUNTS_LEN {
219 return Err(invalid_argument_error());
220 }
221
222 accounts[0].write(InstructionAccount::writable(account.address()));
223
224 accounts[1].write(InstructionAccount::readonly(mint.address()));
225
226 accounts[2].write(InstructionAccount::readonly(owner.address()));
227
228 accounts[3].write(InstructionAccount::readonly(rent_sysvar.address()));
229
230 Ok(InitializeAccount::ACCOUNTS_LEN)
231}
232
233#[inline(always)]
234fn write_instruction_data(data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
235 if data.len() < InitializeAccount::DATA_LEN {
236 return Err(invalid_argument_error());
237 }
238
239 data[0].write(InitializeAccount::DISCRIMINATOR);
240
241 Ok(InitializeAccount::DATA_LEN)
242}