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}