Skip to main content

pinocchio_token/state/
multisig.rs

1use {
2    crate::{instructions::MAX_MULTISIG_SIGNERS, ID},
3    core::mem::size_of,
4    solana_account_view::{AccountView, Ref},
5    solana_address::Address,
6    solana_program_error::ProgramError,
7};
8
9/// Multisignature data.
10#[repr(C)]
11pub struct Multisig {
12    /// Number of signers required
13    m: u8,
14    /// Number of valid signers
15    n: u8,
16    /// Is `true` if this structure has been initialized
17    is_initialized: u8,
18    /// Signer public keys
19    signers: [Address; MAX_MULTISIG_SIGNERS],
20}
21
22impl Multisig {
23    /// The length of the `Multisig` account data.
24    pub const LEN: usize = size_of::<Multisig>();
25
26    /// Return a `Multisig` from the given account view.
27    ///
28    /// This method performs owner and length validation on `AccountView`, safe
29    /// borrowing the account data.
30    #[inline]
31    pub fn from_account_view(
32        account_view: &AccountView,
33    ) -> Result<Ref<'_, Multisig>, ProgramError> {
34        if account_view.data_len() != Self::LEN {
35            return Err(ProgramError::InvalidAccountData);
36        }
37        if !account_view.owned_by(&ID) {
38            return Err(ProgramError::InvalidAccountOwner);
39        }
40        Ok(Ref::map(account_view.try_borrow()?, |data| unsafe {
41            Self::from_bytes_unchecked(data)
42        }))
43    }
44
45    /// Return a `Multisig` from the given account view.
46    ///
47    /// This method performs owner and length validation on `AccountView`, but
48    /// does not perform the borrow check.
49    ///
50    /// # Safety
51    ///
52    /// The caller must ensure that it is safe to borrow the account data (e.g.,
53    /// there are no mutable borrows of the account data).
54    #[inline]
55    pub unsafe fn from_account_view_unchecked(
56        account_view: &AccountView,
57    ) -> Result<&Self, ProgramError> {
58        if account_view.data_len() != Self::LEN {
59            return Err(ProgramError::InvalidAccountData);
60        }
61        if account_view.owner() != &ID {
62            return Err(ProgramError::InvalidAccountOwner);
63        }
64        Ok(Self::from_bytes_unchecked(account_view.borrow_unchecked()))
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
72    /// `Multisig`, and it has the correct length to be interpreted as an
73    /// instance of `Multisig`.
74    #[inline(always)]
75    pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
76        &*(bytes.as_ptr() as *const Multisig)
77    }
78
79    /// Number of signers required to validate the `Multisig` signature.
80    #[inline(always)]
81    pub const fn required_signers(&self) -> u8 {
82        self.m
83    }
84
85    /// Number of signer addresses present on the `Multisig`.
86    #[inline(always)]
87    pub const fn signers_len(&self) -> usize {
88        self.n as usize
89    }
90
91    /// Return the signer addresses of the `Multisig`.
92    #[inline(always)]
93    pub fn signers(&self) -> &[Address] {
94        // SAFETY: `self.signers` is an array of `Address` with a fixed size of
95        // `MAX_MULTISIG_SIGNERS`; `self.signers_len` is always `<=
96        // MAX_MULTISIG_SIGNERS` and indicates how many of these signers are
97        // valid.
98        unsafe { self.signers.get_unchecked(..self.signers_len()) }
99    }
100
101    /// Check whether the multisig is initialized or not.
102    //
103    // It will return a boolean value indicating whether [`self.is_initialized`]
104    // is different than `0` or not.
105    #[inline(always)]
106    pub fn is_initialized(&self) -> bool {
107        self.is_initialized != 0
108    }
109}