pinocchio_token/state/
mint.rs

1use pinocchio::{
2    account_info::{AccountInfo, Ref},
3    program_error::ProgramError,
4    pubkey::Pubkey,
5};
6
7use crate::ID;
8
9/// Mint data.
10#[repr(C)]
11pub struct Mint {
12    /// Indicates whether the mint authority is present or not.
13    mint_authority_flag: [u8; 4],
14
15    /// Optional authority used to mint new tokens. The mint authority may only
16    /// be provided during mint creation. If no mint authority is present
17    /// then the mint has a fixed supply and no further tokens may be
18    /// minted.
19    mint_authority: Pubkey,
20
21    /// Total supply of tokens.
22    supply: [u8; 8],
23
24    /// Number of base 10 digits to the right of the decimal place.
25    decimals: u8,
26
27    /// Is `true` if this structure has been initialized.
28    is_initialized: u8,
29
30    /// Indicates whether the freeze authority is present or not.
31    freeze_authority_flag: [u8; 4],
32
33    /// Optional authority to freeze token accounts.
34    freeze_authority: Pubkey,
35}
36
37impl Mint {
38    /// The length of the `Mint` account data.
39    pub const LEN: usize = core::mem::size_of::<Mint>();
40
41    /// Return a `Mint` from the given account info.
42    ///
43    /// This method performs owner and length validation on `AccountInfo`, safe borrowing
44    /// the account data.
45    #[inline]
46    pub fn from_account_info(account_info: &AccountInfo) -> Result<Ref<Mint>, ProgramError> {
47        if account_info.data_len() != Self::LEN {
48            return Err(ProgramError::InvalidAccountData);
49        }
50        if !account_info.is_owned_by(&ID) {
51            return Err(ProgramError::InvalidAccountOwner);
52        }
53        Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe {
54            Self::from_bytes_unchecked(data)
55        }))
56    }
57
58    /// Return a `Mint` from the given account info.
59    ///
60    /// This method performs owner and length validation on `AccountInfo`, but does not
61    /// perform the borrow check.
62    ///
63    /// # Safety
64    ///
65    /// The caller must ensure that it is safe to borrow the account data (e.g., there are
66    /// no mutable borrows of the account data).
67    #[inline]
68    pub unsafe fn from_account_info_unchecked(
69        account_info: &AccountInfo,
70    ) -> Result<&Self, ProgramError> {
71        if account_info.data_len() != Self::LEN {
72            return Err(ProgramError::InvalidAccountData);
73        }
74        if account_info.owner() != &ID {
75            return Err(ProgramError::InvalidAccountOwner);
76        }
77        Ok(Self::from_bytes_unchecked(
78            account_info.borrow_data_unchecked(),
79        ))
80    }
81
82    /// Return a `Mint` from the given bytes.
83    ///
84    /// # Safety
85    ///
86    /// The caller must ensure that `bytes` contains a valid representation of `Mint`, and
87    /// it is properly aligned to be interpreted as an instance of `Mint`.
88    /// At the moment `Mint` has an alignment of 1 byte.
89    /// This method does not perform a length validation.
90    #[inline(always)]
91    pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
92        &*(bytes.as_ptr() as *const Mint)
93    }
94
95    #[inline(always)]
96    pub fn has_mint_authority(&self) -> bool {
97        self.mint_authority_flag[0] == 1
98    }
99
100    pub fn mint_authority(&self) -> Option<&Pubkey> {
101        if self.has_mint_authority() {
102            Some(self.mint_authority_unchecked())
103        } else {
104            None
105        }
106    }
107
108    /// Return the mint authority.
109    ///
110    /// This method should be used when the caller knows that the mint will have a mint
111    /// authority set since it skips the `Option` check.
112    #[inline(always)]
113    pub fn mint_authority_unchecked(&self) -> &Pubkey {
114        &self.mint_authority
115    }
116
117    pub fn supply(&self) -> u64 {
118        u64::from_le_bytes(self.supply)
119    }
120
121    pub fn decimals(&self) -> u8 {
122        self.decimals
123    }
124
125    pub fn is_initialized(&self) -> bool {
126        self.is_initialized == 1
127    }
128
129    #[inline(always)]
130    pub fn has_freeze_authority(&self) -> bool {
131        self.freeze_authority_flag[0] == 1
132    }
133
134    pub fn freeze_authority(&self) -> Option<&Pubkey> {
135        if self.has_freeze_authority() {
136            Some(self.freeze_authority_unchecked())
137        } else {
138            None
139        }
140    }
141
142    /// Return the freeze authority.
143    ///
144    /// This method should be used when the caller knows that the mint will have a freeze
145    /// authority set since it skips the `Option` check.
146    #[inline(always)]
147    pub fn freeze_authority_unchecked(&self) -> &Pubkey {
148        &self.freeze_authority
149    }
150}