apl_associated_token_account/
lib.rs1mod tools;
4
5use arch_program::{
6 account::{next_account_info, AccountInfo, AccountMeta},
7 entrypoint::ProgramResult,
8 instruction::Instruction,
9 msg,
10 program::invoke,
11 program_error::ProgramError,
12 program_pack::Pack,
13 pubkey::Pubkey,
14};
15use tools::{create_pda_account, create_pda_account_with_anchor};
16
17#[cfg(not(feature = "no-entrypoint"))]
18use arch_program::entrypoint;
19
20arch_program::declare_id!("ATok9pxLsNzM5zJJ3UQpXBrMriHpZiY5Yio3GKYU4we3");
21
22#[cfg(not(feature = "no-entrypoint"))]
23entrypoint!(process_instruction);
24
25pub fn process_instruction(
27 program_id: &Pubkey,
28 accounts: &[AccountInfo],
29 input: &[u8],
30) -> ProgramResult {
31 let account_info_iter = &mut accounts.iter();
32
33 let funder_info = next_account_info(account_info_iter)?;
34 let associated_token_account_info = next_account_info(account_info_iter)?;
35 let wallet_account_info = next_account_info(account_info_iter)?;
36 let spl_token_mint_info = next_account_info(account_info_iter)?;
37 let system_program_info = next_account_info(account_info_iter)?;
38 let spl_token_program_info = next_account_info(account_info_iter)?;
39 let spl_token_program_id = spl_token_program_info.key;
40
41 let (associated_token_address, bump_seed) = get_associated_token_address_and_bump_seed(
42 wallet_account_info.key,
43 spl_token_mint_info.key,
44 program_id,
45 );
46 if associated_token_address != *associated_token_account_info.key {
47 msg!("Error: Associated address does not match seed derivation");
48 return Err(ProgramError::InvalidSeeds);
49 }
50
51 let associated_token_account_signer_seeds: &[&[_]] = &[
52 &wallet_account_info.key.serialize(),
53 &apl_token::id().serialize(),
54 &spl_token_mint_info.key.serialize(),
55 &[bump_seed],
56 ];
57
58 if input.len() == 36 {
59 let txid: [u8; 32] = input[..32].try_into().unwrap();
60 let vout = u32::from_le_bytes(input[32..36].try_into().unwrap());
61
62 create_pda_account_with_anchor(
63 funder_info,
64 apl_token::state::Account::LEN,
65 spl_token_program_info.key,
66 txid,
67 vout,
68 system_program_info,
69 associated_token_account_info,
70 associated_token_account_signer_seeds,
71 )?;
72 } else {
73 create_pda_account(
74 funder_info,
75 apl_token::state::Account::LEN,
76 spl_token_program_info.key,
77 system_program_info,
78 associated_token_account_info,
79 associated_token_account_signer_seeds,
80 )?;
81 }
82
83 msg!("Initialize the associated token account");
84 invoke(
85 &apl_token::instruction::initialize_account3(
86 spl_token_program_id,
87 associated_token_account_info.key,
88 spl_token_mint_info.key,
89 wallet_account_info.key,
90 )?,
91 &[
92 associated_token_account_info.clone(),
93 spl_token_mint_info.clone(),
94 wallet_account_info.clone(),
95 spl_token_program_info.clone(),
96 ],
97 )
98}
99
100pub fn get_associated_token_address_and_bump_seed(
101 wallet_address: &Pubkey,
102 spl_token_mint_address: &Pubkey,
103 program_id: &Pubkey,
104) -> (Pubkey, u8) {
105 Pubkey::find_program_address(
106 &[
107 &wallet_address.serialize(),
108 &apl_token::id().serialize(),
109 &spl_token_mint_address.serialize(),
110 ],
111 program_id,
112 )
113}
114
115pub fn create_associated_token_account(
116 funder: &Pubkey,
117 associated_token_account: &Pubkey,
118 wallet: &Pubkey,
119 mint: &Pubkey,
120 spl_token_program: &Pubkey,
121 system_program: &Pubkey,
122) -> Instruction {
123 Instruction::new(
124 id(),
125 vec![],
126 vec![
127 AccountMeta::new(*funder, true),
128 AccountMeta::new(*associated_token_account, false),
129 AccountMeta::new_readonly(*wallet, false),
130 AccountMeta::new_readonly(*mint, false),
131 AccountMeta::new_readonly(*system_program, false),
132 AccountMeta::new_readonly(*spl_token_program, false),
133 ],
134 )
135}
136
137#[allow(clippy::too_many_arguments)]
138pub fn create_associated_token_account_with_anchor(
139 funder: &Pubkey,
140 associated_token_account: &Pubkey,
141 wallet: &Pubkey,
142 mint: &Pubkey,
143 spl_token_program: &Pubkey,
144 system_program: &Pubkey,
145 txid: [u8; 32],
146 vout: u32,
147) -> Instruction {
148 let mut data = txid.to_vec();
149 data.extend_from_slice(&vout.to_le_bytes());
150
151 Instruction::new(
152 id(),
153 data,
154 vec![
155 AccountMeta::new(*funder, true),
156 AccountMeta::new(*associated_token_account, false),
157 AccountMeta::new_readonly(*wallet, false),
158 AccountMeta::new_readonly(*mint, false),
159 AccountMeta::new_readonly(*system_program, false),
160 AccountMeta::new_readonly(*spl_token_program, false),
161 ],
162 )
163}