pinocchio_token/instructions/
initialize_multisig.rs

1use core::{mem::MaybeUninit, slice};
2
3use solana_account_view::AccountView;
4use solana_instruction_view::{cpi::invoke_with_bounds, InstructionAccount, InstructionView};
5use solana_program_error::{ProgramError, ProgramResult};
6
7/// Maximum number of multisignature signers.
8pub const MAX_MULTISIG_SIGNERS: usize = 11;
9
10/// Initialize a new Multisig.
11///
12/// ### Accounts:
13///   0. `[writable]` The multisig account to initialize.
14///   1. `[]` Rent sysvar
15///   2. ..`2+N`. `[]` The N signer accounts, where N is between 1 and 11.
16pub struct InitializeMultisig<'a, 'b>
17where
18    'a: 'b,
19{
20    /// Multisig Account.
21    pub multisig: &'a AccountView,
22    /// Rent sysvar Account.
23    pub rent_sysvar: &'a AccountView,
24    /// Signer Accounts
25    pub signers: &'b [&'a AccountView],
26    /// The number of signers (M) required to validate this multisignature
27    /// account.
28    pub m: u8,
29}
30
31impl InitializeMultisig<'_, '_> {
32    #[inline(always)]
33    pub fn invoke(&self) -> ProgramResult {
34        let &Self {
35            multisig,
36            rent_sysvar,
37            signers,
38            m,
39        } = self;
40
41        if signers.len() > MAX_MULTISIG_SIGNERS {
42            return Err(ProgramError::InvalidArgument);
43        }
44
45        let num_accounts = 2 + signers.len();
46
47        // Instruction accounts
48        const UNINIT_INSTRUCTION_ACCOUNT: MaybeUninit<InstructionAccount> =
49            MaybeUninit::<InstructionAccount>::uninit();
50        let mut instruction_accounts = [UNINIT_INSTRUCTION_ACCOUNT; 2 + MAX_MULTISIG_SIGNERS];
51
52        unsafe {
53            // SAFETY:
54            // - `instruction_accounts` is sized to 2 + MAX_MULTISIG_SIGNERS
55            // - Index 0 and 1 are always present
56            instruction_accounts
57                .get_unchecked_mut(0)
58                .write(InstructionAccount::writable(multisig.address()));
59            instruction_accounts
60                .get_unchecked_mut(1)
61                .write(InstructionAccount::readonly(rent_sysvar.address()));
62        }
63
64        for (instruction_account, signer) in
65            instruction_accounts[2..].iter_mut().zip(signers.iter())
66        {
67            instruction_account.write(InstructionAccount::readonly(signer.address()));
68        }
69
70        // Instruction data layout:
71        // -  [0]: instruction discriminator (1 byte, u8)
72        // -  [1]: m (1 byte, u8)
73        let data = &[2, m];
74
75        let instruction = InstructionView {
76            program_id: &crate::ID,
77            accounts: unsafe {
78                slice::from_raw_parts(instruction_accounts.as_ptr() as _, num_accounts)
79            },
80            data,
81        };
82
83        // Account view array
84        const UNINIT_VIEW: MaybeUninit<&AccountView> = MaybeUninit::uninit();
85        let mut acc_views = [UNINIT_VIEW; 2 + MAX_MULTISIG_SIGNERS];
86
87        unsafe {
88            // SAFETY:
89            // - `account_views` is sized to 2 + MAX_MULTISIG_SIGNERS
90            // - Index 0 and 1 are always present
91            acc_views.get_unchecked_mut(0).write(multisig);
92            acc_views.get_unchecked_mut(1).write(rent_sysvar);
93        }
94
95        // Fill signer accounts
96        for (account_view, signer) in acc_views[2..].iter_mut().zip(signers.iter()) {
97            account_view.write(signer);
98        }
99
100        invoke_with_bounds::<{ 2 + MAX_MULTISIG_SIGNERS }>(&instruction, unsafe {
101            slice::from_raw_parts(acc_views.as_ptr() as _, num_accounts)
102        })
103    }
104}