pinocchio_token/instructions/
initialize_multisig.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 const MAX_MULTISIG_SIGNERS: usize = 11;
17
18pub struct InitializeMultisig<'account, 'multisig, MultisigSigner: AsRef<AccountView>>
38where
39 'account: 'multisig,
40{
41 pub multisig: &'account AccountView,
43
44 pub rent_sysvar: &'account AccountView,
46
47 pub multisig_signers: &'multisig [MultisigSigner],
49
50 pub m: u8,
53}
54
55impl<'account, 'multisig, MultisigSigner: AsRef<AccountView>>
56 InitializeMultisig<'account, 'multisig, MultisigSigner>
57where
58 'account: 'multisig,
59{
60 pub const DISCRIMINATOR: u8 = 2;
61
62 pub const MAX_ACCOUNTS_LEN: usize = 2 + MAX_MULTISIG_SIGNERS;
68
69 pub const DATA_LEN: usize = 2;
73
74 #[inline(always)]
75 pub fn new(
76 multisig: &'account AccountView,
77 rent_sysvar: &'account AccountView,
78 multisig_signers: &'multisig [MultisigSigner],
79 m: u8,
80 ) -> Self {
81 Self {
82 multisig,
83 rent_sysvar,
84 multisig_signers,
85 m,
86 }
87 }
88
89 #[inline(always)]
90 pub fn invoke(&self) -> ProgramResult {
91 if self.multisig_signers.len() > MAX_MULTISIG_SIGNERS {
92 return Err(ProgramError::InvalidArgument);
93 }
94
95 let mut instruction_accounts =
96 [UNINIT_INSTRUCTION_ACCOUNT; InitializeMultisig::<&AccountView>::MAX_ACCOUNTS_LEN];
97 let written_instruction_accounts =
98 self.write_instruction_accounts(&mut instruction_accounts)?;
99
100 let mut accounts =
101 [UNINIT_CPI_ACCOUNT; InitializeMultisig::<&AccountView>::MAX_ACCOUNTS_LEN];
102 let written_accounts = self.write_accounts(&mut accounts)?;
103
104 let mut instruction_data = [UNINIT_BYTE; InitializeMultisig::<&AccountView>::DATA_LEN];
105 let written_instruction_data = self.write_instruction_data(&mut instruction_data)?;
106
107 unsafe {
108 invoke_unchecked(
109 &InstructionView {
110 program_id: &crate::ID,
111 accounts: from_raw_parts(
112 instruction_accounts.as_ptr() as _,
113 written_instruction_accounts,
114 ),
115 data: from_raw_parts(instruction_data.as_ptr() as _, written_instruction_data),
116 },
117 from_raw_parts(accounts.as_ptr() as _, written_accounts),
118 );
119 }
120
121 Ok(())
122 }
123}
124
125impl<MultisigSigner: AsRef<AccountView>> CpiWriter for InitializeMultisig<'_, '_, MultisigSigner> {
126 #[inline(always)]
127 fn write_accounts<'cpi>(
128 &self,
129 accounts: &mut [MaybeUninit<CpiAccount<'cpi>>],
130 ) -> Result<usize, ProgramError>
131 where
132 Self: 'cpi,
133 {
134 write_accounts(
135 self.multisig,
136 self.rent_sysvar,
137 self.multisig_signers,
138 accounts,
139 )
140 }
141
142 #[inline(always)]
143 fn write_instruction_accounts<'cpi>(
144 &self,
145 accounts: &mut [MaybeUninit<InstructionAccount<'cpi>>],
146 ) -> Result<usize, ProgramError>
147 where
148 Self: 'cpi,
149 {
150 write_instruction_accounts(
151 self.multisig,
152 self.rent_sysvar,
153 self.multisig_signers,
154 accounts,
155 )
156 }
157
158 #[inline(always)]
159 fn write_instruction_data(&self, data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
160 write_instruction_data(self.m, data)
161 }
162}
163
164impl<MultisigSigner: AsRef<AccountView>> super::IntoBatch
165 for InitializeMultisig<'_, '_, MultisigSigner>
166{
167 #[inline(always)]
168 fn into_batch<'account, 'state>(
169 self,
170 batch: &mut super::Batch<'account, 'state>,
171 ) -> ProgramResult
172 where
173 Self: 'account + 'state,
174 {
175 batch.push(
176 |accounts| {
177 write_accounts(
178 self.multisig,
179 self.rent_sysvar,
180 self.multisig_signers,
181 accounts,
182 )
183 },
184 |accounts| {
185 write_instruction_accounts(
186 self.multisig,
187 self.rent_sysvar,
188 self.multisig_signers,
189 accounts,
190 )
191 },
192 |data| write_instruction_data(self.m, data),
193 )
194 }
195}
196
197#[inline(always)]
198fn write_accounts<'account, 'multisig, 'out, MultisigSigner: AsRef<AccountView>>(
199 multisig: &'account AccountView,
200 rent_sysvar: &'account AccountView,
201 multisig_signers: &'multisig [MultisigSigner],
202 accounts: &mut [MaybeUninit<CpiAccount<'out>>],
203) -> Result<usize, ProgramError>
204where
205 'account: 'out,
206 'multisig: 'out,
207{
208 let expected_accounts = 2 + multisig_signers.len();
209
210 if expected_accounts > accounts.len() {
211 return Err(invalid_argument_error());
212 }
213
214 if multisig.is_borrowed() {
215 return Err(account_borrow_failed_error());
216 }
217
218 CpiAccount::init_from_account_view(multisig, &mut accounts[0]);
219
220 CpiAccount::init_from_account_view(rent_sysvar, &mut accounts[1]);
221
222 for (account, signer) in accounts[2..expected_accounts]
223 .iter_mut()
224 .zip(multisig_signers.iter())
225 {
226 CpiAccount::init_from_account_view(signer.as_ref(), account);
227 }
228
229 Ok(expected_accounts)
230}
231
232#[inline(always)]
233fn write_instruction_accounts<'account, 'multisig, 'out, MultisigSigner: AsRef<AccountView>>(
234 multisig: &'account AccountView,
235 rent_sysvar: &'account AccountView,
236 multisig_signers: &'multisig [MultisigSigner],
237 accounts: &mut [MaybeUninit<InstructionAccount<'out>>],
238) -> Result<usize, ProgramError>
239where
240 'account: 'out,
241 'multisig: 'out,
242{
243 let expected_accounts = 2 + multisig_signers.len();
244
245 if expected_accounts > accounts.len() {
246 return Err(invalid_argument_error());
247 }
248
249 accounts[0].write(InstructionAccount::writable(multisig.address()));
250
251 accounts[1].write(InstructionAccount::readonly(rent_sysvar.address()));
252
253 for (account, signer) in accounts[2..expected_accounts]
254 .iter_mut()
255 .zip(multisig_signers.iter())
256 {
257 account.write(InstructionAccount::readonly(signer.as_ref().address()));
258 }
259
260 Ok(expected_accounts)
261}
262
263#[inline(always)]
264fn write_instruction_data(m: u8, data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
265 if data.len() < InitializeMultisig::<&AccountView>::DATA_LEN {
266 return Err(invalid_argument_error());
267 }
268
269 data[0].write(InitializeMultisig::<&AccountView>::DISCRIMINATOR);
270
271 data[1].write(m);
272
273 Ok(InitializeMultisig::<&AccountView>::DATA_LEN)
274}