Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions programs/token-2022/src/instructions/initialize_multisig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use core::{mem::MaybeUninit, slice};

use pinocchio::{
account_info::AccountInfo,
cpi::invoke_with_bounds,
instruction::{AccountMeta, Instruction},
program_error::ProgramError,
pubkey::Pubkey,
ProgramResult,
};

/// Maximum number of multisignature signers.
pub const MAX_MULTISIG_SIGNERS: usize = 11;

/// Initialize a new Multisig.
///
/// ### Accounts:
/// 0. `[writable]` The multisig account to initialize.
/// 1. `[]` Rent sysvar
/// 2. `..+N` `[]` The `N` signer accounts, where `N` is `1 <=
/// N <= 11`.
pub struct InitializeMultisig<'a, 'b, 'c>
where
'a: 'b,
{
/// Multisig Account.
pub multisig: &'a AccountInfo,
/// Rent sysvar Account.
pub rent_sysvar: &'a AccountInfo,
/// Signer Accounts
pub signers: &'b [&'a AccountInfo],
/// The number of signers (M) required to validate this multisignature
/// account.
pub m: u8,
/// Token Program.
pub token_program: &'c Pubkey,
}

impl InitializeMultisig<'_, '_, '_> {
#[inline(always)]
pub fn invoke(&self) -> ProgramResult {
let &Self {
multisig,
rent_sysvar,
signers,
m,
token_program,
} = self;

if signers.len() > MAX_MULTISIG_SIGNERS {
return Err(ProgramError::InvalidArgument);
}

let num_accounts = 2 + signers.len();

// Account metadata
const UNINIT_META: MaybeUninit<AccountMeta> = MaybeUninit::<AccountMeta>::uninit();
let mut acc_metas = [UNINIT_META; 2 + MAX_MULTISIG_SIGNERS];

unsafe {
// SAFETY:
// - `account_metas` is sized to 2 + MAX_MULTISIG_SIGNERS
// - Index 0 and 1 are always present
acc_metas
.get_unchecked_mut(0)
.write(AccountMeta::writable(multisig.key()));
acc_metas
.get_unchecked_mut(1)
.write(AccountMeta::readonly(rent_sysvar.key()));
}

for (account_meta, signer) in acc_metas[2..].iter_mut().zip(signers.iter()) {
account_meta.write(AccountMeta::readonly(signer.key()));
}

// Instruction data layout:
// - [0]: instruction discriminator (1 byte, u8)
// - [1]: m (1 byte, u8)
let data = &[2, m];

let instruction = Instruction {
program_id: token_program,
accounts: unsafe { slice::from_raw_parts(acc_metas.as_ptr() as _, num_accounts) },
data,
};

// Account info array
const UNINIT_INFO: MaybeUninit<&AccountInfo> = MaybeUninit::uninit();
let mut acc_infos = [UNINIT_INFO; 2 + MAX_MULTISIG_SIGNERS];

unsafe {
// SAFETY:
// - `account_infos` is sized to 2 + MAX_MULTISIG_SIGNERS
// - Index 0 and 1 are always present
acc_infos.get_unchecked_mut(0).write(multisig);
acc_infos.get_unchecked_mut(1).write(rent_sysvar);
}

// Fill signer accounts
for (account_info, signer) in acc_infos[2..].iter_mut().zip(signers.iter()) {
account_info.write(signer);
}

invoke_with_bounds::<{ 2 + MAX_MULTISIG_SIGNERS }>(&instruction, unsafe {
slice::from_raw_parts(acc_infos.as_ptr() as _, num_accounts)
})
}
}
99 changes: 99 additions & 0 deletions programs/token-2022/src/instructions/initialize_multisig_2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use core::{mem::MaybeUninit, slice};

use pinocchio::{
account_info::AccountInfo,
cpi::invoke_with_bounds,
instruction::{AccountMeta, Instruction},
program_error::ProgramError,
pubkey::Pubkey,
ProgramResult,
};

use crate::instructions::MAX_MULTISIG_SIGNERS;

/// Initialize a new Multisig.
///
/// ### Accounts:
/// 0. `[writable]` The multisig account to initialize.
/// 1. `..+N` `[]` The `N` signer accounts, where `N` is `1 <=
/// N <= 11`.
pub struct InitializeMultisig2<'a, 'b, 'c>
where
'a: 'b,
{
/// Multisig Account.
pub multisig: &'a AccountInfo,
/// Signer Accounts
pub signers: &'b [&'a AccountInfo],
/// The number of signers (M) required to validate this multisignature
/// account.
pub m: u8,
/// Token Program.
pub token_program: &'c Pubkey,
}

impl InitializeMultisig2<'_, '_, '_> {
#[inline(always)]
pub fn invoke(&self) -> ProgramResult {
let &Self {
multisig,
signers,
m,
token_program,
} = self;

if signers.len() > MAX_MULTISIG_SIGNERS {
return Err(ProgramError::InvalidArgument);
}

let num_accounts = 1 + signers.len();

// Account metadata
const UNINIT_META: MaybeUninit<AccountMeta> = MaybeUninit::<AccountMeta>::uninit();
let mut acc_metas = [UNINIT_META; 1 + MAX_MULTISIG_SIGNERS];

unsafe {
// SAFETY:
// - `account_metas` is sized to 1 + MAX_MULTISIG_SIGNERS
// - Index 0 is always present
acc_metas
.get_unchecked_mut(0)
.write(AccountMeta::writable(multisig.key()));
}

for (account_meta, signer) in acc_metas[1..].iter_mut().zip(signers.iter()) {
account_meta.write(AccountMeta::readonly(signer.key()));
}

// Instruction data layout:
// - [0]: instruction discriminator (1 byte, u8)
// - [1]: m (1 byte, u8)
let data = &[19, m];

let instruction = Instruction {
program_id: token_program,
accounts: unsafe { slice::from_raw_parts(acc_metas.as_ptr() as _, num_accounts) },
data,
};

// Account info array
const UNINIT_INFO: MaybeUninit<&AccountInfo> = MaybeUninit::uninit();
let mut acc_infos = [UNINIT_INFO; 1 + MAX_MULTISIG_SIGNERS];

unsafe {
// SAFETY:
// - `account_infos` is sized to 1 + MAX_MULTISIG_SIGNERS
// - Index 0 is always present
acc_infos.get_unchecked_mut(0).write(multisig);
}

// Fill signer accounts
for (account_info, signer) in acc_infos[1..].iter_mut().zip(signers.iter()) {
account_info.write(signer);
}

invoke_with_bounds::<{ 1 + MAX_MULTISIG_SIGNERS }>(&instruction, unsafe {
slice::from_raw_parts(acc_infos.as_ptr() as _, num_accounts)
})
}
}
4 changes: 4 additions & 0 deletions programs/token-2022/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ mod initialize_account_2;
mod initialize_account_3;
mod initialize_mint;
mod initialize_mint_2;
mod initialize_multisig;
mod initialize_multisig_2;
mod mint_to;
mod mint_to_checked;
mod revoke;
Expand All @@ -29,6 +31,8 @@ pub use initialize_account_2::*;
pub use initialize_account_3::*;
pub use initialize_mint::*;
pub use initialize_mint_2::*;
pub use initialize_multisig::*;
pub use initialize_multisig_2::*;
pub use mint_to::*;
pub use mint_to_checked::*;
pub use revoke::*;
Expand Down