Skip to main content

pinocchio_token/state/
mint.rs

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