Skip to main content

pinocchio_token/instructions/
initialize_multisig_2.rs

1use {
2    crate::{
3        instructions::{
4            account_borrow_failed_error, invalid_argument_error, CpiWriter, MAX_MULTISIG_SIGNERS,
5        },
6        UNINIT_BYTE, UNINIT_CPI_ACCOUNT, UNINIT_INSTRUCTION_ACCOUNT,
7    },
8    core::{mem::MaybeUninit, slice::from_raw_parts},
9    solana_account_view::AccountView,
10    solana_instruction_view::{
11        cpi::{invoke_unchecked, CpiAccount},
12        InstructionAccount, InstructionView,
13    },
14    solana_program_error::{ProgramError, ProgramResult},
15};
16
17/// Like [`super::InitializeMultisig`], but does not require the
18/// Rent sysvar to be provided
19///
20/// Accounts expected by this instruction:
21///
22///   0. `[writable]` The multisignature account to initialize.
23///   1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <=
24///      11`.
25pub struct InitializeMultisig2<'account, 'multisig, MultisigSigner: AsRef<AccountView>>
26where
27    'account: 'multisig,
28{
29    /// The multisignature account to initialize.
30    pub multisig: &'account AccountView,
31
32    ///  The signer accounts.
33    pub multisig_signers: &'multisig [MultisigSigner],
34
35    /// The number of signers (M) required to validate this multisignature
36    /// account.
37    pub m: u8,
38}
39
40impl<'account, 'multisig, MultisigSigner: AsRef<AccountView>>
41    InitializeMultisig2<'account, 'multisig, MultisigSigner>
42where
43    'account: 'multisig,
44{
45    pub const DISCRIMINATOR: u8 = 19;
46
47    /// Maximum number of accounts expected by this instruction.
48    ///
49    /// The required number of accounts will depend whether the
50    /// source account has a single owner or a multisignature
51    /// owner.
52    pub const MAX_ACCOUNTS_LEN: usize = 1 + MAX_MULTISIG_SIGNERS;
53
54    /// Instruction data length:
55    ///   - discriminator (1 byte)
56    ///   - number of signers (1 byte)
57    pub const DATA_LEN: usize = 2;
58
59    #[inline(always)]
60    pub fn new(
61        multisig: &'account AccountView,
62        multisig_signers: &'multisig [MultisigSigner],
63        m: u8,
64    ) -> Self {
65        Self {
66            multisig,
67            multisig_signers,
68            m,
69        }
70    }
71
72    #[inline(always)]
73    pub fn invoke(&self) -> ProgramResult {
74        if self.multisig_signers.len() > MAX_MULTISIG_SIGNERS {
75            return Err(ProgramError::InvalidArgument);
76        }
77
78        let mut instruction_accounts =
79            [UNINIT_INSTRUCTION_ACCOUNT; InitializeMultisig2::<&AccountView>::MAX_ACCOUNTS_LEN];
80        let written_instruction_accounts =
81            self.write_instruction_accounts(&mut instruction_accounts)?;
82
83        let mut accounts =
84            [UNINIT_CPI_ACCOUNT; InitializeMultisig2::<&AccountView>::MAX_ACCOUNTS_LEN];
85        let written_accounts = self.write_accounts(&mut accounts)?;
86
87        let mut instruction_data = [UNINIT_BYTE; InitializeMultisig2::<&AccountView>::DATA_LEN];
88        let written_instruction_data = self.write_instruction_data(&mut instruction_data)?;
89
90        unsafe {
91            invoke_unchecked(
92                &InstructionView {
93                    program_id: &crate::ID,
94                    accounts: from_raw_parts(
95                        instruction_accounts.as_ptr() as _,
96                        written_instruction_accounts,
97                    ),
98                    data: from_raw_parts(instruction_data.as_ptr() as _, written_instruction_data),
99                },
100                from_raw_parts(accounts.as_ptr() as _, written_accounts),
101            );
102        }
103
104        Ok(())
105    }
106}
107
108impl<MultisigSigner: AsRef<AccountView>> CpiWriter for InitializeMultisig2<'_, '_, MultisigSigner> {
109    #[inline(always)]
110    fn write_accounts<'cpi>(
111        &self,
112        accounts: &mut [MaybeUninit<CpiAccount<'cpi>>],
113    ) -> Result<usize, ProgramError>
114    where
115        Self: 'cpi,
116    {
117        write_accounts(self.multisig, self.multisig_signers, accounts)
118    }
119
120    #[inline(always)]
121    fn write_instruction_accounts<'cpi>(
122        &self,
123        accounts: &mut [MaybeUninit<InstructionAccount<'cpi>>],
124    ) -> Result<usize, ProgramError>
125    where
126        Self: 'cpi,
127    {
128        write_instruction_accounts(self.multisig, self.multisig_signers, accounts)
129    }
130
131    #[inline(always)]
132    fn write_instruction_data(&self, data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
133        write_instruction_data(self.m, data)
134    }
135}
136
137impl<MultisigSigner: AsRef<AccountView>> super::IntoBatch
138    for InitializeMultisig2<'_, '_, MultisigSigner>
139{
140    #[inline(always)]
141    fn into_batch<'account, 'state>(
142        self,
143        batch: &mut super::Batch<'account, 'state>,
144    ) -> ProgramResult
145    where
146        Self: 'account + 'state,
147    {
148        batch.push(
149            |accounts| write_accounts(self.multisig, self.multisig_signers, accounts),
150            |accounts| write_instruction_accounts(self.multisig, self.multisig_signers, accounts),
151            |data| write_instruction_data(self.m, data),
152        )
153    }
154}
155
156#[inline(always)]
157fn write_accounts<'account, 'multisig, 'out, MultisigSigner: AsRef<AccountView>>(
158    multisig: &'account AccountView,
159    multisig_signers: &'multisig [MultisigSigner],
160    accounts: &mut [MaybeUninit<CpiAccount<'out>>],
161) -> Result<usize, ProgramError>
162where
163    'account: 'out,
164    'multisig: 'out,
165{
166    let expected_accounts = 1 + multisig_signers.len();
167
168    if expected_accounts > accounts.len() {
169        return Err(invalid_argument_error());
170    }
171
172    if multisig.is_borrowed() {
173        return Err(account_borrow_failed_error());
174    }
175
176    CpiAccount::init_from_account_view(multisig, &mut accounts[0]);
177
178    for (account, signer) in accounts[1..expected_accounts]
179        .iter_mut()
180        .zip(multisig_signers.iter())
181    {
182        CpiAccount::init_from_account_view(signer.as_ref(), account);
183    }
184
185    Ok(expected_accounts)
186}
187
188#[inline(always)]
189fn write_instruction_accounts<'account, 'multisig, 'out, MultisigSigner: AsRef<AccountView>>(
190    multisig: &'account AccountView,
191    multisig_signers: &'multisig [MultisigSigner],
192    accounts: &mut [MaybeUninit<InstructionAccount<'out>>],
193) -> Result<usize, ProgramError>
194where
195    'account: 'out,
196    'multisig: 'out,
197{
198    let expected_accounts = 1 + multisig_signers.len();
199
200    if expected_accounts > accounts.len() {
201        return Err(invalid_argument_error());
202    }
203
204    accounts[0].write(InstructionAccount::writable(multisig.address()));
205
206    for (account, signer) in accounts[1..expected_accounts]
207        .iter_mut()
208        .zip(multisig_signers.iter())
209    {
210        account.write(InstructionAccount::readonly(signer.as_ref().address()));
211    }
212
213    Ok(expected_accounts)
214}
215
216#[inline(always)]
217fn write_instruction_data(m: u8, data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
218    if data.len() < InitializeMultisig2::<&AccountView>::DATA_LEN {
219        return Err(invalid_argument_error());
220    }
221
222    data[0].write(InitializeMultisig2::<&AccountView>::DISCRIMINATOR);
223
224    data[1].write(m);
225
226    Ok(InitializeMultisig2::<&AccountView>::DATA_LEN)
227}