pinocchio_token/state/
mint.rs

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