Skip to content

Commit b017ffa

Browse files
committed
feat: add multisig state
1 parent 97608da commit b017ffa

File tree

5 files changed

+194
-1
lines changed

5 files changed

+194
-1
lines changed

Cargo.lock

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
mod account_state;
22
mod mint;
3+
mod multisig;
34
mod token;
45

56
pub use account_state::*;
67
pub use mint::*;
8+
pub use multisig::*;
79
pub use token::*;
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use pinocchio::{
2+
account_info::{AccountInfo, Ref},
3+
program_error::ProgramError,
4+
pubkey::Pubkey,
5+
};
6+
7+
use crate::{instructions::MAX_MULTISIG_SIGNERS, ID};
8+
9+
/// Multisignature data.
10+
#[repr(C)]
11+
pub struct Multisig {
12+
/// Number of signers required
13+
pub m: u8,
14+
/// Number of valid signers
15+
pub n: u8,
16+
/// Is `true` if this structure has been initialized
17+
pub is_initialized: u8,
18+
/// Signer public keys
19+
pub signers: [Pubkey; MAX_MULTISIG_SIGNERS],
20+
}
21+
22+
impl Multisig {
23+
/// The length of the `Multisig` account data.
24+
pub const LEN: usize = core::mem::size_of::<Multisig>();
25+
26+
/// Return a `Multisig` from the given account info.
27+
///
28+
/// This method performs owner and length validation on `AccountInfo`, safe borrowing
29+
/// the account data.
30+
#[inline]
31+
pub fn from_account_info(account_info: &AccountInfo) -> Result<Ref<Multisig>, ProgramError> {
32+
if account_info.data_len() != Self::LEN {
33+
return Err(ProgramError::InvalidAccountData);
34+
}
35+
if !account_info.is_owned_by(&ID) {
36+
return Err(ProgramError::InvalidAccountOwner);
37+
}
38+
Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe {
39+
Self::from_bytes_unchecked(data)
40+
}))
41+
}
42+
43+
/// Return a `Multisig` from the given account info.
44+
///
45+
/// This method performs owner and length validation on `AccountInfo`, but does not
46+
/// perform the borrow check.
47+
///
48+
/// # Safety
49+
///
50+
/// The caller must ensure that it is safe to borrow the account data (e.g., there are
51+
/// no mutable borrows of the account data).
52+
#[inline]
53+
pub unsafe fn from_account_info_unchecked(
54+
account_info: &AccountInfo,
55+
) -> Result<&Self, ProgramError> {
56+
if account_info.data_len() != Self::LEN {
57+
return Err(ProgramError::InvalidAccountData);
58+
}
59+
if account_info.owner() != &ID {
60+
return Err(ProgramError::InvalidAccountOwner);
61+
}
62+
Ok(Self::from_bytes_unchecked(
63+
account_info.borrow_data_unchecked(),
64+
))
65+
}
66+
67+
/// Return a `Multisig` from the given bytes.
68+
///
69+
/// # Safety
70+
///
71+
/// The caller must ensure that `bytes` contains a valid representation of `Multisig`, and
72+
/// it is properly aligned to be interpreted as an instance of `Multisig`.
73+
/// At the moment `Multisig` has an alignment of 1 byte.
74+
/// This method does not perform a length validation.
75+
#[inline(always)]
76+
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
77+
&*(bytes.as_ptr() as *const Multisig)
78+
}
79+
80+
#[inline(always)]
81+
pub fn required_signers(&self) -> u8 {
82+
self.m
83+
}
84+
85+
pub fn valid_signers(&self) -> u8 {
86+
self.n
87+
}
88+
89+
#[inline(always)]
90+
pub fn signers(&self) -> &[Pubkey; MAX_MULTISIG_SIGNERS] {
91+
&self.signers
92+
}
93+
}

programs/token/src/state/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
mod account_state;
22
mod mint;
3+
mod multisig;
34
mod token;
45

56
pub use account_state::*;
67
pub use mint::*;
8+
pub use multisig::*;
79
pub use token::*;
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use pinocchio::{
2+
account_info::{AccountInfo, Ref},
3+
program_error::ProgramError,
4+
pubkey::Pubkey,
5+
};
6+
7+
use crate::{instructions::MAX_MULTISIG_SIGNERS, ID};
8+
9+
/// Multisignature data.
10+
#[repr(C)]
11+
pub struct Multisig {
12+
/// Number of signers required
13+
pub m: u8,
14+
/// Number of valid signers
15+
pub n: u8,
16+
/// Is `true` if this structure has been initialized
17+
pub is_initialized: u8,
18+
/// Signer public keys
19+
pub signers: [Pubkey; MAX_MULTISIG_SIGNERS],
20+
}
21+
22+
impl Multisig {
23+
/// The length of the `Multisig` account data.
24+
pub const LEN: usize = core::mem::size_of::<Multisig>();
25+
26+
/// Return a `Multisig` from the given account info.
27+
///
28+
/// This method performs owner and length validation on `AccountInfo`, safe borrowing
29+
/// the account data.
30+
#[inline]
31+
pub fn from_account_info(account_info: &AccountInfo) -> Result<Ref<Multisig>, ProgramError> {
32+
if account_info.data_len() != Self::LEN {
33+
return Err(ProgramError::InvalidAccountData);
34+
}
35+
if !account_info.is_owned_by(&ID) {
36+
return Err(ProgramError::InvalidAccountOwner);
37+
}
38+
Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe {
39+
Self::from_bytes_unchecked(data)
40+
}))
41+
}
42+
43+
/// Return a `Multisig` from the given account info.
44+
///
45+
/// This method performs owner and length validation on `AccountInfo`, but does not
46+
/// perform the borrow check.
47+
///
48+
/// # Safety
49+
///
50+
/// The caller must ensure that it is safe to borrow the account data (e.g., there are
51+
/// no mutable borrows of the account data).
52+
#[inline]
53+
pub unsafe fn from_account_info_unchecked(
54+
account_info: &AccountInfo,
55+
) -> Result<&Self, ProgramError> {
56+
if account_info.data_len() != Self::LEN {
57+
return Err(ProgramError::InvalidAccountData);
58+
}
59+
if account_info.owner() != &ID {
60+
return Err(ProgramError::InvalidAccountOwner);
61+
}
62+
Ok(Self::from_bytes_unchecked(
63+
account_info.borrow_data_unchecked(),
64+
))
65+
}
66+
67+
/// Return a `Multisig` from the given bytes.
68+
///
69+
/// # Safety
70+
///
71+
/// The caller must ensure that `bytes` contains a valid representation of `Multisig`, and
72+
/// it is properly aligned to be interpreted as an instance of `Multisig`.
73+
/// At the moment `Multisig` has an alignment of 1 byte.
74+
/// This method does not perform a length validation.
75+
#[inline(always)]
76+
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
77+
&*(bytes.as_ptr() as *const Multisig)
78+
}
79+
80+
#[inline(always)]
81+
pub fn required_signers(&self) -> u8 {
82+
self.m
83+
}
84+
85+
pub fn valid_signers(&self) -> u8 {
86+
self.n
87+
}
88+
89+
#[inline(always)]
90+
pub fn signers(&self) -> &[Pubkey; MAX_MULTISIG_SIGNERS] {
91+
&self.signers
92+
}
93+
}

0 commit comments

Comments
 (0)