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