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