Skip to content

Commit 98ee441

Browse files
committed
add init multisig ix
1 parent 78a8b44 commit 98ee441

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use core::slice::from_raw_parts;
2+
3+
use pinocchio::{
4+
account_info::AccountInfo,
5+
instruction::{AccountMeta, Instruction, Signer},
6+
program::invoke_signed,
7+
program_error::ProgramError,
8+
ProgramResult,
9+
};
10+
11+
extern crate alloc;
12+
13+
use alloc::vec::Vec;
14+
15+
use crate::{write_bytes, UNINIT_BYTE};
16+
17+
/// Initialize a new Multisig.
18+
///
19+
/// ### Accounts:
20+
/// 0. `[writable]` The multisig account to initialize.
21+
/// 1. `[]` Rent sysvar
22+
/// 2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
23+
/// 11`.
24+
pub struct InitializeMultisig<'a> {
25+
/// Multisig Account.
26+
pub multisig: &'a AccountInfo,
27+
/// Rent sysvar Account.
28+
pub rent_sysvar: &'a AccountInfo,
29+
/// Signer Accounts
30+
pub multisig_signers: Vec<&'a AccountInfo>,
31+
/// The number of signers (M) required to validate this multisignature
32+
/// account.
33+
pub m: u8,
34+
}
35+
36+
impl InitializeMultisig<'_> {
37+
#[inline(always)]
38+
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
39+
self.invoke_signed::<ACCOUNTS>(&[])
40+
}
41+
42+
pub fn invoke_signed<const ACCOUNTS: usize>(&self, signers: &[Signer]) -> ProgramResult {
43+
if ACCOUNTS != self.multisig_signers.len() + 2 {
44+
return Err(ProgramError::InvalidArgument);
45+
}
46+
47+
// Account metadata
48+
let mut account_metas = Vec::with_capacity(1 + self.multisig_signers.len());
49+
account_metas.push(AccountMeta::writable(self.multisig.key()));
50+
51+
account_metas.extend(
52+
self.multisig_signers
53+
.iter()
54+
.map(|a| AccountMeta::readonly(a.key())),
55+
);
56+
57+
// Instruction data layout:
58+
// - [0]: instruction discriminator (1 byte, u8)
59+
// - [1]: m (1 byte, u8)
60+
let mut instruction_data = [UNINIT_BYTE; 2];
61+
62+
// Set discriminator as u8 at offset [0]
63+
write_bytes(&mut instruction_data, &[2]);
64+
// Set number of signers (m) at offset 1
65+
write_bytes(&mut instruction_data[1..2], &[self.m]);
66+
67+
let instruction = Instruction {
68+
program_id: &crate::ID,
69+
accounts: account_metas.as_slice(),
70+
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
71+
};
72+
73+
let mut account_infos = Vec::with_capacity(2 + self.multisig_signers.len());
74+
75+
account_infos.push(self.multisig);
76+
77+
account_infos.extend_from_slice(self.multisig_signers.as_slice());
78+
79+
let account_infos: [&AccountInfo; ACCOUNTS] = account_infos
80+
.try_into()
81+
.map_err(|_| ProgramError::InvalidArgument)?;
82+
83+
invoke_signed(&instruction, &account_infos, signers)
84+
}
85+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use core::slice::from_raw_parts;
2+
3+
use pinocchio::{
4+
account_info::AccountInfo,
5+
instruction::{AccountMeta, Instruction, Signer},
6+
program::invoke_signed,
7+
program_error::ProgramError,
8+
ProgramResult,
9+
};
10+
11+
extern crate alloc;
12+
13+
use alloc::vec::Vec;
14+
15+
use crate::{write_bytes, UNINIT_BYTE};
16+
17+
/// Initialize a new Multisig.
18+
///
19+
/// ### Accounts:
20+
/// 0. `[writable]` The multisig account to initialize.
21+
/// 1. `[]` Rent sysvar
22+
/// 2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
23+
/// 11`.
24+
pub struct InitializeMultisig2<'a> {
25+
/// Multisig Account.
26+
pub multisig: &'a AccountInfo,
27+
/// Signer Accounts
28+
pub multisig_signers: Vec<&'a AccountInfo>,
29+
/// The number of signers (M) required to validate this multisignature
30+
/// account.
31+
pub m: u8,
32+
}
33+
34+
impl InitializeMultisig2<'_> {
35+
#[inline(always)]
36+
pub fn invoke<const ACCOUNTS: usize>(&self) -> ProgramResult {
37+
self.invoke_signed::<ACCOUNTS>(&[])
38+
}
39+
40+
pub fn invoke_signed<const ACCOUNTS: usize>(&self, signers: &[Signer]) -> ProgramResult {
41+
if ACCOUNTS != self.multisig_signers.len() + 1 {
42+
return Err(ProgramError::InvalidArgument);
43+
}
44+
45+
// Account metadata
46+
let mut account_metas = Vec::with_capacity(1 + self.multisig_signers.len());
47+
account_metas.push(AccountMeta::writable(self.multisig.key()));
48+
49+
account_metas.extend(
50+
self.multisig_signers
51+
.iter()
52+
.map(|a| AccountMeta::readonly(a.key())),
53+
);
54+
55+
// Instruction data layout:
56+
// - [0]: instruction discriminator (1 byte, u8)
57+
// - [1]: m (1 byte, u8)
58+
let mut instruction_data = [UNINIT_BYTE; 2];
59+
60+
// Set discriminator as u8 at offset [0]
61+
write_bytes(&mut instruction_data, &[2]);
62+
// Set number of signers (m) at offset 1
63+
write_bytes(&mut instruction_data[1..2], &[self.m]);
64+
65+
let instruction = Instruction {
66+
program_id: &crate::ID,
67+
accounts: account_metas.as_slice(),
68+
data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 2) },
69+
};
70+
71+
let mut account_infos = Vec::with_capacity(1 + self.multisig_signers.len());
72+
73+
account_infos.push(self.multisig);
74+
75+
account_infos.extend_from_slice(self.multisig_signers.as_slice());
76+
77+
let account_infos: [&AccountInfo; ACCOUNTS] = account_infos
78+
.try_into()
79+
.map_err(|_| ProgramError::InvalidArgument)?;
80+
81+
invoke_signed(&instruction, &account_infos, signers)
82+
}
83+
}

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)