1use anchor_lang::solana_program::account_info::AccountInfo;
2
3use anchor_lang::solana_program::program_pack::Pack;
4use anchor_lang::solana_program::pubkey::Pubkey;
5use anchor_lang::{context::CpiContext, Accounts};
6use anchor_lang::{solana_program, Result};
7use std::ops::Deref;
8
9pub use spl_token;
10pub use spl_token::ID;
11
12pub fn transfer<'a, 'b, 'c, 'info>(
13 ctx: CpiContext<'a, 'b, 'c, 'info, Transfer<'info>>,
14 amount: u64,
15) -> Result<()> {
16 let ix = spl_token::instruction::transfer(
17 &spl_token::ID,
18 ctx.accounts.from.key,
19 ctx.accounts.to.key,
20 ctx.accounts.authority.key,
21 &[],
22 amount,
23 )?;
24 solana_program::program::invoke_signed(
25 &ix,
26 &[
27 ctx.accounts.from.clone(),
28 ctx.accounts.to.clone(),
29 ctx.accounts.authority.clone(),
30 ],
31 ctx.signer_seeds,
32 )
33 .map_err(Into::into)
34}
35
36pub fn mint_to<'a, 'b, 'c, 'info>(
37 ctx: CpiContext<'a, 'b, 'c, 'info, MintTo<'info>>,
38 amount: u64,
39) -> Result<()> {
40 let ix = spl_token::instruction::mint_to(
41 &spl_token::ID,
42 ctx.accounts.mint.key,
43 ctx.accounts.to.key,
44 ctx.accounts.authority.key,
45 &[],
46 amount,
47 )?;
48 solana_program::program::invoke_signed(
49 &ix,
50 &[
51 ctx.accounts.to.clone(),
52 ctx.accounts.mint.clone(),
53 ctx.accounts.authority.clone(),
54 ],
55 ctx.signer_seeds,
56 )
57 .map_err(Into::into)
58}
59
60pub fn burn<'a, 'b, 'c, 'info>(
61 ctx: CpiContext<'a, 'b, 'c, 'info, Burn<'info>>,
62 amount: u64,
63) -> Result<()> {
64 let ix = spl_token::instruction::burn(
65 &spl_token::ID,
66 ctx.accounts.from.key,
67 ctx.accounts.mint.key,
68 ctx.accounts.authority.key,
69 &[],
70 amount,
71 )?;
72 solana_program::program::invoke_signed(
73 &ix,
74 &[
75 ctx.accounts.from.clone(),
76 ctx.accounts.mint.clone(),
77 ctx.accounts.authority.clone(),
78 ],
79 ctx.signer_seeds,
80 )
81 .map_err(Into::into)
82}
83
84pub fn approve<'a, 'b, 'c, 'info>(
85 ctx: CpiContext<'a, 'b, 'c, 'info, Approve<'info>>,
86 amount: u64,
87) -> Result<()> {
88 let ix = spl_token::instruction::approve(
89 &spl_token::ID,
90 ctx.accounts.to.key,
91 ctx.accounts.delegate.key,
92 ctx.accounts.authority.key,
93 &[],
94 amount,
95 )?;
96 solana_program::program::invoke_signed(
97 &ix,
98 &[
99 ctx.accounts.to.clone(),
100 ctx.accounts.delegate.clone(),
101 ctx.accounts.authority.clone(),
102 ],
103 ctx.signer_seeds,
104 )
105 .map_err(Into::into)
106}
107
108pub fn revoke<'a, 'b, 'c, 'info>(ctx: CpiContext<'a, 'b, 'c, 'info, Revoke<'info>>) -> Result<()> {
109 let ix = spl_token::instruction::revoke(
110 &spl_token::ID,
111 ctx.accounts.source.key,
112 ctx.accounts.authority.key,
113 &[],
114 )?;
115 solana_program::program::invoke_signed(
116 &ix,
117 &[ctx.accounts.source.clone(), ctx.accounts.authority.clone()],
118 ctx.signer_seeds,
119 )
120 .map_err(Into::into)
121}
122
123pub fn initialize_account<'a, 'b, 'c, 'info>(
124 ctx: CpiContext<'a, 'b, 'c, 'info, InitializeAccount<'info>>,
125) -> Result<()> {
126 let ix = spl_token::instruction::initialize_account(
127 &spl_token::ID,
128 ctx.accounts.account.key,
129 ctx.accounts.mint.key,
130 ctx.accounts.authority.key,
131 )?;
132 solana_program::program::invoke_signed(
133 &ix,
134 &[
135 ctx.accounts.account.clone(),
136 ctx.accounts.mint.clone(),
137 ctx.accounts.authority.clone(),
138 ctx.accounts.rent.clone(),
139 ],
140 ctx.signer_seeds,
141 )
142 .map_err(Into::into)
143}
144
145pub fn close_account<'a, 'b, 'c, 'info>(
146 ctx: CpiContext<'a, 'b, 'c, 'info, CloseAccount<'info>>,
147) -> Result<()> {
148 let ix = spl_token::instruction::close_account(
149 &spl_token::ID,
150 ctx.accounts.account.key,
151 ctx.accounts.destination.key,
152 ctx.accounts.authority.key,
153 &[], )?;
155 solana_program::program::invoke_signed(
156 &ix,
157 &[
158 ctx.accounts.account.clone(),
159 ctx.accounts.destination.clone(),
160 ctx.accounts.authority.clone(),
161 ],
162 ctx.signer_seeds,
163 )
164 .map_err(Into::into)
165}
166
167pub fn freeze_account<'a, 'b, 'c, 'info>(
168 ctx: CpiContext<'a, 'b, 'c, 'info, FreezeAccount<'info>>,
169) -> Result<()> {
170 let ix = spl_token::instruction::freeze_account(
171 &spl_token::ID,
172 ctx.accounts.account.key,
173 ctx.accounts.mint.key,
174 ctx.accounts.authority.key,
175 &[], )?;
177 solana_program::program::invoke_signed(
178 &ix,
179 &[
180 ctx.accounts.account.clone(),
181 ctx.accounts.mint.clone(),
182 ctx.accounts.authority.clone(),
183 ],
184 ctx.signer_seeds,
185 )
186 .map_err(Into::into)
187}
188
189pub fn thaw_account<'a, 'b, 'c, 'info>(
190 ctx: CpiContext<'a, 'b, 'c, 'info, ThawAccount<'info>>,
191) -> Result<()> {
192 let ix = spl_token::instruction::thaw_account(
193 &spl_token::ID,
194 ctx.accounts.account.key,
195 ctx.accounts.mint.key,
196 ctx.accounts.authority.key,
197 &[], )?;
199 solana_program::program::invoke_signed(
200 &ix,
201 &[
202 ctx.accounts.account.clone(),
203 ctx.accounts.mint.clone(),
204 ctx.accounts.authority.clone(),
205 ],
206 ctx.signer_seeds,
207 )
208 .map_err(Into::into)
209}
210
211pub fn initialize_mint<'a, 'b, 'c, 'info>(
212 ctx: CpiContext<'a, 'b, 'c, 'info, InitializeMint<'info>>,
213 decimals: u8,
214 authority: &Pubkey,
215 freeze_authority: Option<&Pubkey>,
216) -> Result<()> {
217 let ix = spl_token::instruction::initialize_mint(
218 &spl_token::ID,
219 ctx.accounts.mint.key,
220 authority,
221 freeze_authority,
222 decimals,
223 )?;
224 solana_program::program::invoke_signed(
225 &ix,
226 &[ctx.accounts.mint.clone(), ctx.accounts.rent.clone()],
227 ctx.signer_seeds,
228 )
229 .map_err(Into::into)
230}
231
232pub fn set_authority<'a, 'b, 'c, 'info>(
233 ctx: CpiContext<'a, 'b, 'c, 'info, SetAuthority<'info>>,
234 authority_type: spl_token::instruction::AuthorityType,
235 new_authority: Option<Pubkey>,
236) -> Result<()> {
237 let mut spl_new_authority: Option<&Pubkey> = None;
238 if new_authority.is_some() {
239 spl_new_authority = new_authority.as_ref()
240 }
241
242 let ix = spl_token::instruction::set_authority(
243 &spl_token::ID,
244 ctx.accounts.account_or_mint.key,
245 spl_new_authority,
246 authority_type,
247 ctx.accounts.current_authority.key,
248 &[], )?;
250 solana_program::program::invoke_signed(
251 &ix,
252 &[
253 ctx.accounts.account_or_mint.clone(),
254 ctx.accounts.current_authority.clone(),
255 ],
256 ctx.signer_seeds,
257 )
258 .map_err(Into::into)
259}
260
261pub fn sync_native<'a, 'b, 'c, 'info>(
262 ctx: CpiContext<'a, 'b, 'c, 'info, SyncNative<'info>>,
263) -> Result<()> {
264 let ix = spl_token::instruction::sync_native(&spl_token::ID, ctx.accounts.account.key)?;
265 solana_program::program::invoke_signed(&ix, &[ctx.accounts.account.clone()], ctx.signer_seeds)
266 .map_err(Into::into)
267}
268
269#[derive(Accounts)]
270pub struct Transfer<'info> {
271 pub from: AccountInfo<'info>,
272 pub to: AccountInfo<'info>,
273 pub authority: AccountInfo<'info>,
274}
275
276#[derive(Accounts)]
277pub struct MintTo<'info> {
278 pub mint: AccountInfo<'info>,
279 pub to: AccountInfo<'info>,
280 pub authority: AccountInfo<'info>,
281}
282
283#[derive(Accounts)]
284pub struct Burn<'info> {
285 pub mint: AccountInfo<'info>,
286 pub from: AccountInfo<'info>,
287 pub authority: AccountInfo<'info>,
288}
289
290#[derive(Accounts)]
291pub struct Approve<'info> {
292 pub to: AccountInfo<'info>,
293 pub delegate: AccountInfo<'info>,
294 pub authority: AccountInfo<'info>,
295}
296
297#[derive(Accounts)]
298pub struct Revoke<'info> {
299 pub source: AccountInfo<'info>,
300 pub authority: AccountInfo<'info>,
301}
302
303#[derive(Accounts)]
304pub struct InitializeAccount<'info> {
305 pub account: AccountInfo<'info>,
306 pub mint: AccountInfo<'info>,
307 pub authority: AccountInfo<'info>,
308 pub rent: AccountInfo<'info>,
309}
310
311#[derive(Accounts)]
312pub struct CloseAccount<'info> {
313 pub account: AccountInfo<'info>,
314 pub destination: AccountInfo<'info>,
315 pub authority: AccountInfo<'info>,
316}
317
318#[derive(Accounts)]
319pub struct FreezeAccount<'info> {
320 pub account: AccountInfo<'info>,
321 pub mint: AccountInfo<'info>,
322 pub authority: AccountInfo<'info>,
323}
324
325#[derive(Accounts)]
326pub struct ThawAccount<'info> {
327 pub account: AccountInfo<'info>,
328 pub mint: AccountInfo<'info>,
329 pub authority: AccountInfo<'info>,
330}
331
332#[derive(Accounts)]
333pub struct InitializeMint<'info> {
334 pub mint: AccountInfo<'info>,
335 pub rent: AccountInfo<'info>,
336}
337
338#[derive(Accounts)]
339pub struct SetAuthority<'info> {
340 pub current_authority: AccountInfo<'info>,
341 pub account_or_mint: AccountInfo<'info>,
342}
343
344#[derive(Accounts)]
345pub struct SyncNative<'info> {
346 pub account: AccountInfo<'info>,
347}
348
349#[derive(Clone, Debug, Default, PartialEq)]
350pub struct TokenAccount(spl_token::state::Account);
351
352impl TokenAccount {
353 pub const LEN: usize = spl_token::state::Account::LEN;
354}
355
356impl anchor_lang::AccountDeserialize for TokenAccount {
357 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
358 spl_token::state::Account::unpack(buf)
359 .map(TokenAccount)
360 .map_err(Into::into)
361 }
362}
363
364impl anchor_lang::AccountSerialize for TokenAccount {}
365
366impl anchor_lang::Owner for TokenAccount {
367 fn owner() -> Pubkey {
368 ID
369 }
370}
371
372impl Deref for TokenAccount {
373 type Target = spl_token::state::Account;
374
375 fn deref(&self) -> &Self::Target {
376 &self.0
377 }
378}
379
380#[derive(Clone, Debug, Default, PartialEq)]
381pub struct Mint(spl_token::state::Mint);
382
383impl Mint {
384 pub const LEN: usize = spl_token::state::Mint::LEN;
385}
386
387impl anchor_lang::AccountDeserialize for Mint {
388 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
389 spl_token::state::Mint::unpack(buf)
390 .map(Mint)
391 .map_err(Into::into)
392 }
393}
394
395impl anchor_lang::AccountSerialize for Mint {}
396
397impl anchor_lang::Owner for Mint {
398 fn owner() -> Pubkey {
399 ID
400 }
401}
402
403impl Deref for Mint {
404 type Target = spl_token::state::Mint;
405
406 fn deref(&self) -> &Self::Target {
407 &self.0
408 }
409}
410
411#[derive(Clone)]
412pub struct Token;
413
414impl anchor_lang::Id for Token {
415 fn id() -> Pubkey {
416 ID
417 }
418}
419
420pub mod accessor {
423 use super::*;
424
425 pub fn amount(account: &AccountInfo) -> Result<u64> {
426 let bytes = account.try_borrow_data()?;
427 let mut amount_bytes = [0u8; 8];
428 amount_bytes.copy_from_slice(&bytes[64..72]);
429 Ok(u64::from_le_bytes(amount_bytes))
430 }
431
432 pub fn mint(account: &AccountInfo) -> Result<Pubkey> {
433 let bytes = account.try_borrow_data()?;
434 let mut mint_bytes = [0u8; 32];
435 mint_bytes.copy_from_slice(&bytes[..32]);
436 Ok(Pubkey::new_from_array(mint_bytes))
437 }
438
439 pub fn authority(account: &AccountInfo) -> Result<Pubkey> {
440 let bytes = account.try_borrow_data()?;
441 let mut owner_bytes = [0u8; 32];
442 owner_bytes.copy_from_slice(&bytes[32..64]);
443 Ok(Pubkey::new_from_array(owner_bytes))
444 }
445}