Skip to content

Commit 096a066

Browse files
authored
feat : Add InitMultisig ixs (#197)
* add init multisig ix * chore : resolve comments and refactor
1 parent b77195a commit 096a066

File tree

3 files changed

+201
-0
lines changed

3 files changed

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

programs/token/src/instructions/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ mod initialize_account_2;
99
mod initialize_account_3;
1010
mod initialize_mint;
1111
mod initialize_mint_2;
12+
mod initialize_multisig;
13+
mod initialize_multisig_2;
1214
mod mint_to;
1315
mod mint_to_checked;
1416
mod revoke;
@@ -29,6 +31,8 @@ pub use initialize_account_2::*;
2931
pub use initialize_account_3::*;
3032
pub use initialize_mint::*;
3133
pub use initialize_mint_2::*;
34+
pub use initialize_multisig::*;
35+
pub use initialize_multisig_2::*;
3236
pub use mint_to::*;
3337
pub use mint_to_checked::*;
3438
pub use revoke::*;

0 commit comments

Comments
 (0)