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}