safe_associated_token_account/
instruction.rs1use {
4 crate::{get_associated_token_address_with_program_id, id},
5 assert_matches::assert_matches,
6 borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
7 solana_program::{
8 instruction::{AccountMeta, Instruction},
9 pubkey::Pubkey,
10 },
11};
12
13#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
15pub enum AssociatedTokenAccountInstruction {
16 Create,
26 CreateIdempotent,
37 RecoverNested,
56}
57
58fn build_associated_token_account_instruction(
59 funding_address: &Pubkey,
60 wallet_address: &Pubkey,
61 token_mint_address: &Pubkey,
62 token_program_id: &Pubkey,
63 instruction: AssociatedTokenAccountInstruction,
64) -> Instruction {
65 let associated_account_address = get_associated_token_address_with_program_id(
66 wallet_address,
67 token_mint_address,
68 token_program_id,
69 );
70 assert_matches!(
72 instruction,
73 AssociatedTokenAccountInstruction::Create
74 | AssociatedTokenAccountInstruction::CreateIdempotent
75 );
76 Instruction {
77 program_id: id(),
78 accounts: vec![
79 AccountMeta::new(*funding_address, true),
80 AccountMeta::new(associated_account_address, false),
81 AccountMeta::new_readonly(*wallet_address, false),
82 AccountMeta::new_readonly(*token_mint_address, false),
83 AccountMeta::new_readonly(solana_program::system_program::id(), false),
84 AccountMeta::new_readonly(*token_program_id, false),
85 ],
86 data: instruction.try_to_vec().unwrap(),
87 }
88}
89
90pub fn create_associated_token_account(
92 funding_address: &Pubkey,
93 wallet_address: &Pubkey,
94 token_mint_address: &Pubkey,
95 token_program_id: &Pubkey,
96) -> Instruction {
97 build_associated_token_account_instruction(
98 funding_address,
99 wallet_address,
100 token_mint_address,
101 token_program_id,
102 AssociatedTokenAccountInstruction::Create,
103 )
104}
105
106pub fn create_associated_token_account_idempotent(
108 funding_address: &Pubkey,
109 wallet_address: &Pubkey,
110 token_mint_address: &Pubkey,
111 token_program_id: &Pubkey,
112) -> Instruction {
113 build_associated_token_account_instruction(
114 funding_address,
115 wallet_address,
116 token_mint_address,
117 token_program_id,
118 AssociatedTokenAccountInstruction::CreateIdempotent,
119 )
120}
121
122pub fn recover_nested(
124 wallet_address: &Pubkey,
125 owner_token_mint_address: &Pubkey,
126 nested_token_mint_address: &Pubkey,
127 token_program_id: &Pubkey,
128) -> Instruction {
129 let owner_associated_account_address = get_associated_token_address_with_program_id(
130 wallet_address,
131 owner_token_mint_address,
132 token_program_id,
133 );
134 let destination_associated_account_address = get_associated_token_address_with_program_id(
135 wallet_address,
136 nested_token_mint_address,
137 token_program_id,
138 );
139 let nested_associated_account_address = get_associated_token_address_with_program_id(
140 &owner_associated_account_address, nested_token_mint_address,
142 token_program_id,
143 );
144
145 let instruction_data = AssociatedTokenAccountInstruction::RecoverNested;
146
147 Instruction {
148 program_id: id(),
149 accounts: vec![
150 AccountMeta::new(nested_associated_account_address, false),
151 AccountMeta::new_readonly(*nested_token_mint_address, false),
152 AccountMeta::new(destination_associated_account_address, false),
153 AccountMeta::new_readonly(owner_associated_account_address, false),
154 AccountMeta::new_readonly(*owner_token_mint_address, false),
155 AccountMeta::new(*wallet_address, true),
156 AccountMeta::new_readonly(*token_program_id, false),
157 ],
158 data: instruction_data.try_to_vec().unwrap(),
159 }
160}