manifest/validation/
token_checkers.rs1use crate::require;
2use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};
3use spl_token_2022::{
4 check_spl_token_program_account, extension::StateWithExtensions, state::Mint,
5};
6use std::ops::Deref;
7
8#[derive(Clone)]
9pub struct MintAccountInfo<'a, 'info> {
10 pub mint: Mint,
11 pub info: &'a AccountInfo<'info>,
12}
13
14impl<'a, 'info> MintAccountInfo<'a, 'info> {
15 pub fn new(info: &'a AccountInfo<'info>) -> Result<MintAccountInfo<'a, 'info>, ProgramError> {
16 check_spl_token_program_account(info.owner)?;
17
18 let mint: Mint = StateWithExtensions::<Mint>::unpack(&info.data.borrow())?.base;
19
20 Ok(Self { mint, info })
21 }
22}
23
24impl<'a, 'info> AsRef<AccountInfo<'info>> for MintAccountInfo<'a, 'info> {
25 fn as_ref(&self) -> &AccountInfo<'info> {
26 self.info
27 }
28}
29
30#[derive(Clone)]
31pub struct TokenAccountInfo<'a, 'info> {
32 pub info: &'a AccountInfo<'info>,
33}
34
35impl<'a, 'info> TokenAccountInfo<'a, 'info> {
36 pub fn new(
37 info: &'a AccountInfo<'info>,
38 mint: &Pubkey,
39 ) -> Result<TokenAccountInfo<'a, 'info>, ProgramError> {
40 require!(
41 info.owner == &spl_token::id() || info.owner == &spl_token_2022::id(),
42 ProgramError::IllegalOwner,
43 "Token account must be owned by the Token Program",
44 )?;
45 require!(
47 &info.try_borrow_data()?[0..32] == mint.as_ref(),
48 ProgramError::InvalidAccountData,
49 "Token account mint mismatch",
50 )?;
51 Ok(Self { info })
52 }
53
54 pub fn get_owner(&self) -> Pubkey {
55 Pubkey::new_from_array(
56 self.info.try_borrow_data().unwrap()[32..64]
57 .try_into()
58 .unwrap(),
59 )
60 }
61
62 pub fn get_balance_atoms(&self) -> u64 {
63 u64::from_le_bytes(
64 self.info.try_borrow_data().unwrap()[64..72]
65 .try_into()
66 .unwrap(),
67 )
68 }
69
70 pub fn new_with_owner(
71 info: &'a AccountInfo<'info>,
72 mint: &Pubkey,
73 owner: &Pubkey,
74 ) -> Result<TokenAccountInfo<'a, 'info>, ProgramError> {
75 let token_account_info = Self::new(info, mint)?;
76 require!(
78 &info.try_borrow_data()?[32..64] == owner.as_ref(),
79 ProgramError::IllegalOwner,
80 "Token account owner mismatch",
81 )?;
82 Ok(token_account_info)
83 }
84
85 pub fn new_with_owner_and_key(
86 info: &'a AccountInfo<'info>,
87 mint: &Pubkey,
88 owner: &Pubkey,
89 key: &Pubkey,
90 ) -> Result<TokenAccountInfo<'a, 'info>, ProgramError> {
91 require!(
92 info.key == key,
93 ProgramError::InvalidInstructionData,
94 "Invalid pubkey for Token Account",
95 )?;
96 Self::new_with_owner(info, mint, owner)
97 }
98}
99
100impl<'a, 'info> AsRef<AccountInfo<'info>> for TokenAccountInfo<'a, 'info> {
101 fn as_ref(&self) -> &AccountInfo<'info> {
102 self.info
103 }
104}
105
106impl<'a, 'info> Deref for TokenAccountInfo<'a, 'info> {
107 type Target = AccountInfo<'info>;
108
109 fn deref(&self) -> &Self::Target {
110 self.info
111 }
112}
113
114#[macro_export]
115macro_rules! market_vault_seeds {
116 ( $market:expr, $mint:expr ) => {
117 &[b"vault", $market.as_ref(), $mint.as_ref()]
118 };
119}
120
121#[macro_export]
122macro_rules! market_vault_seeds_with_bump {
123 ( $market:expr, $mint:expr, $bump:expr ) => {
124 &[&[b"vault", $market.as_ref(), $mint.as_ref(), &[$bump]]]
125 };
126}
127
128#[macro_export]
129macro_rules! global_vault_seeds {
130 ( $mint:expr ) => {
131 &[b"global-vault", $mint.as_ref()]
132 };
133}
134
135#[macro_export]
136macro_rules! global_vault_seeds_with_bump {
137 ( $mint:expr, $bump:expr ) => {
138 &[&[b"global-vault", $mint.as_ref(), &[$bump]]]
139 };
140}
141
142pub fn get_vault_address(market: &Pubkey, mint: &Pubkey) -> (Pubkey, u8) {
143 Pubkey::find_program_address(market_vault_seeds!(market, mint), &crate::ID)
144}
145
146pub fn get_global_vault_address(mint: &Pubkey) -> (Pubkey, u8) {
147 Pubkey::find_program_address(global_vault_seeds!(mint), &crate::ID)
148}