Skip to main content

anchor_spl/
token_2022.rs

1// Avoiding AccountInfo deprecated msg in anchor context
2#![allow(deprecated)]
3use anchor_lang::{
4    context::CpiContext,
5    solana_program::{account_info::AccountInfo, pubkey::Pubkey},
6    Accounts, Result,
7};
8pub use {spl_token_2022::ID, spl_token_2022_interface as spl_token_2022};
9
10#[deprecated(
11    since = "0.28.0",
12    note = "please use `transfer_checked` or `transfer_checked_with_fee` instead"
13)]
14pub fn transfer<'info>(
15    ctx: CpiContext<'_, '_, '_, 'info, Transfer<'info>>,
16    amount: u64,
17) -> Result<()> {
18    #[allow(deprecated)]
19    let ix = spl_token_2022::instruction::transfer(
20        &ctx.program_id,
21        ctx.accounts.from.key,
22        ctx.accounts.to.key,
23        ctx.accounts.authority.key,
24        &[],
25        amount,
26    )?;
27    anchor_lang::solana_program::program::invoke_signed(
28        &ix,
29        &[ctx.accounts.from, ctx.accounts.to, ctx.accounts.authority],
30        ctx.signer_seeds,
31    )
32    .map_err(Into::into)
33}
34
35pub fn transfer_checked<'info>(
36    ctx: CpiContext<'_, '_, '_, 'info, TransferChecked<'info>>,
37    amount: u64,
38    decimals: u8,
39) -> Result<()> {
40    let ix = spl_token_2022::instruction::transfer_checked(
41        &ctx.program_id,
42        ctx.accounts.from.key,
43        ctx.accounts.mint.key,
44        ctx.accounts.to.key,
45        ctx.accounts.authority.key,
46        &[],
47        amount,
48        decimals,
49    )?;
50    anchor_lang::solana_program::program::invoke_signed(
51        &ix,
52        &[
53            ctx.accounts.from,
54            ctx.accounts.mint,
55            ctx.accounts.to,
56            ctx.accounts.authority,
57        ],
58        ctx.signer_seeds,
59    )
60    .map_err(Into::into)
61}
62
63pub fn mint_to<'info>(
64    ctx: CpiContext<'_, '_, '_, 'info, MintTo<'info>>,
65    amount: u64,
66) -> Result<()> {
67    let ix = spl_token_2022::instruction::mint_to(
68        &ctx.program_id,
69        ctx.accounts.mint.key,
70        ctx.accounts.to.key,
71        ctx.accounts.authority.key,
72        &[],
73        amount,
74    )?;
75    anchor_lang::solana_program::program::invoke_signed(
76        &ix,
77        &[ctx.accounts.to, ctx.accounts.mint, ctx.accounts.authority],
78        ctx.signer_seeds,
79    )
80    .map_err(Into::into)
81}
82
83pub fn mint_to_checked<'info>(
84    ctx: CpiContext<'_, '_, '_, 'info, MintToChecked<'info>>,
85    amount: u64,
86    decimals: u8,
87) -> Result<()> {
88    let ix = spl_token_2022::instruction::mint_to_checked(
89        &ctx.program_id,
90        ctx.accounts.mint.key,
91        ctx.accounts.to.key,
92        ctx.accounts.authority.key,
93        &[],
94        amount,
95        decimals,
96    )?;
97    anchor_lang::solana_program::program::invoke_signed(
98        &ix,
99        &[ctx.accounts.to, ctx.accounts.mint, ctx.accounts.authority],
100        ctx.signer_seeds,
101    )
102    .map_err(Into::into)
103}
104
105pub fn burn<'info>(ctx: CpiContext<'_, '_, '_, 'info, Burn<'info>>, amount: u64) -> Result<()> {
106    let ix = spl_token_2022::instruction::burn(
107        &ctx.program_id,
108        ctx.accounts.from.key,
109        ctx.accounts.mint.key,
110        ctx.accounts.authority.key,
111        &[],
112        amount,
113    )?;
114    anchor_lang::solana_program::program::invoke_signed(
115        &ix,
116        &[ctx.accounts.from, ctx.accounts.mint, ctx.accounts.authority],
117        ctx.signer_seeds,
118    )
119    .map_err(Into::into)
120}
121
122pub fn burn_checked<'info>(
123    ctx: CpiContext<'_, '_, '_, 'info, BurnChecked<'info>>,
124    amount: u64,
125    decimals: u8,
126) -> Result<()> {
127    let ix = spl_token_2022::instruction::burn_checked(
128        &ctx.program_id,
129        ctx.accounts.from.key,
130        ctx.accounts.mint.key,
131        ctx.accounts.authority.key,
132        &[],
133        amount,
134        decimals,
135    )?;
136    anchor_lang::solana_program::program::invoke_signed(
137        &ix,
138        &[ctx.accounts.from, ctx.accounts.mint, ctx.accounts.authority],
139        ctx.signer_seeds,
140    )
141    .map_err(Into::into)
142}
143
144pub fn approve<'info>(
145    ctx: CpiContext<'_, '_, '_, 'info, Approve<'info>>,
146    amount: u64,
147) -> Result<()> {
148    let ix = spl_token_2022::instruction::approve(
149        &ctx.program_id,
150        ctx.accounts.to.key,
151        ctx.accounts.delegate.key,
152        ctx.accounts.authority.key,
153        &[],
154        amount,
155    )?;
156    anchor_lang::solana_program::program::invoke_signed(
157        &ix,
158        &[
159            ctx.accounts.to,
160            ctx.accounts.delegate,
161            ctx.accounts.authority,
162        ],
163        ctx.signer_seeds,
164    )
165    .map_err(Into::into)
166}
167
168pub fn approve_checked<'info>(
169    ctx: CpiContext<'_, '_, '_, 'info, ApproveChecked<'info>>,
170    amount: u64,
171    decimals: u8,
172) -> Result<()> {
173    let ix = spl_token_2022::instruction::approve_checked(
174        &ctx.program_id,
175        ctx.accounts.to.key,
176        ctx.accounts.mint.key,
177        ctx.accounts.delegate.key,
178        ctx.accounts.authority.key,
179        &[],
180        amount,
181        decimals,
182    )?;
183    anchor_lang::solana_program::program::invoke_signed(
184        &ix,
185        &[
186            ctx.accounts.to,
187            ctx.accounts.mint,
188            ctx.accounts.delegate,
189            ctx.accounts.authority,
190        ],
191        ctx.signer_seeds,
192    )
193    .map_err(Into::into)
194}
195
196pub fn revoke<'info>(ctx: CpiContext<'_, '_, '_, 'info, Revoke<'info>>) -> Result<()> {
197    let ix = spl_token_2022::instruction::revoke(
198        &ctx.program_id,
199        ctx.accounts.source.key,
200        ctx.accounts.authority.key,
201        &[],
202    )?;
203    anchor_lang::solana_program::program::invoke_signed(
204        &ix,
205        &[ctx.accounts.source, ctx.accounts.authority],
206        ctx.signer_seeds,
207    )
208    .map_err(Into::into)
209}
210
211pub fn initialize_account<'info>(
212    ctx: CpiContext<'_, '_, '_, 'info, InitializeAccount<'info>>,
213) -> Result<()> {
214    let ix = spl_token_2022::instruction::initialize_account(
215        &ctx.program_id,
216        ctx.accounts.account.key,
217        ctx.accounts.mint.key,
218        ctx.accounts.authority.key,
219    )?;
220    anchor_lang::solana_program::program::invoke(
221        &ix,
222        &[
223            ctx.accounts.account,
224            ctx.accounts.mint,
225            ctx.accounts.authority,
226            ctx.accounts.rent,
227        ],
228    )
229    .map_err(Into::into)
230}
231
232pub fn initialize_account3<'info>(
233    ctx: CpiContext<'_, '_, '_, 'info, InitializeAccount3<'info>>,
234) -> Result<()> {
235    let ix = spl_token_2022::instruction::initialize_account3(
236        &ctx.program_id,
237        ctx.accounts.account.key,
238        ctx.accounts.mint.key,
239        ctx.accounts.authority.key,
240    )?;
241    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account, ctx.accounts.mint])
242        .map_err(Into::into)
243}
244
245pub fn close_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, CloseAccount<'info>>) -> Result<()> {
246    let ix = spl_token_2022::instruction::close_account(
247        &ctx.program_id,
248        ctx.accounts.account.key,
249        ctx.accounts.destination.key,
250        ctx.accounts.authority.key,
251        &[], // TODO: support multisig
252    )?;
253    anchor_lang::solana_program::program::invoke_signed(
254        &ix,
255        &[
256            ctx.accounts.account,
257            ctx.accounts.destination,
258            ctx.accounts.authority,
259        ],
260        ctx.signer_seeds,
261    )
262    .map_err(Into::into)
263}
264
265pub fn freeze_account<'info>(
266    ctx: CpiContext<'_, '_, '_, 'info, FreezeAccount<'info>>,
267) -> Result<()> {
268    let ix = spl_token_2022::instruction::freeze_account(
269        &ctx.program_id,
270        ctx.accounts.account.key,
271        ctx.accounts.mint.key,
272        ctx.accounts.authority.key,
273        &[], // TODO: Support multisig signers.
274    )?;
275    anchor_lang::solana_program::program::invoke_signed(
276        &ix,
277        &[
278            ctx.accounts.account,
279            ctx.accounts.mint,
280            ctx.accounts.authority,
281        ],
282        ctx.signer_seeds,
283    )
284    .map_err(Into::into)
285}
286
287pub fn thaw_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, ThawAccount<'info>>) -> Result<()> {
288    let ix = spl_token_2022::instruction::thaw_account(
289        &ctx.program_id,
290        ctx.accounts.account.key,
291        ctx.accounts.mint.key,
292        ctx.accounts.authority.key,
293        &[], // TODO: Support multisig signers.
294    )?;
295    anchor_lang::solana_program::program::invoke_signed(
296        &ix,
297        &[
298            ctx.accounts.account,
299            ctx.accounts.mint,
300            ctx.accounts.authority,
301        ],
302        ctx.signer_seeds,
303    )
304    .map_err(Into::into)
305}
306
307pub fn initialize_mint<'info>(
308    ctx: CpiContext<'_, '_, '_, 'info, InitializeMint<'info>>,
309    decimals: u8,
310    authority: &Pubkey,
311    freeze_authority: Option<&Pubkey>,
312) -> Result<()> {
313    let ix = spl_token_2022::instruction::initialize_mint(
314        &ctx.program_id,
315        ctx.accounts.mint.key,
316        authority,
317        freeze_authority,
318        decimals,
319    )?;
320    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint, ctx.accounts.rent])
321        .map_err(Into::into)
322}
323
324pub fn initialize_mint2<'info>(
325    ctx: CpiContext<'_, '_, '_, 'info, InitializeMint2<'info>>,
326    decimals: u8,
327    authority: &Pubkey,
328    freeze_authority: Option<&Pubkey>,
329) -> Result<()> {
330    let ix = spl_token_2022::instruction::initialize_mint2(
331        &ctx.program_id,
332        ctx.accounts.mint.key,
333        authority,
334        freeze_authority,
335        decimals,
336    )?;
337    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
338}
339
340pub fn set_authority<'info>(
341    ctx: CpiContext<'_, '_, '_, 'info, SetAuthority<'info>>,
342    authority_type: spl_token_2022::instruction::AuthorityType,
343    new_authority: Option<Pubkey>,
344) -> Result<()> {
345    let ix = spl_token_2022::instruction::set_authority(
346        &ctx.program_id,
347        ctx.accounts.account_or_mint.key,
348        new_authority.as_ref(),
349        authority_type,
350        ctx.accounts.current_authority.key,
351        &[], // TODO: Support multisig signers.
352    )?;
353    anchor_lang::solana_program::program::invoke_signed(
354        &ix,
355        &[ctx.accounts.account_or_mint, ctx.accounts.current_authority],
356        ctx.signer_seeds,
357    )
358    .map_err(Into::into)
359}
360
361pub fn sync_native<'info>(ctx: CpiContext<'_, '_, '_, 'info, SyncNative<'info>>) -> Result<()> {
362    let ix = spl_token_2022::instruction::sync_native(&ctx.program_id, ctx.accounts.account.key)?;
363    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
364}
365
366pub fn get_account_data_size<'info>(
367    ctx: CpiContext<'_, '_, '_, 'info, GetAccountDataSize<'info>>,
368    extension_types: &[spl_token_2022::extension::ExtensionType],
369) -> Result<u64> {
370    let ix = spl_token_2022::instruction::get_account_data_size(
371        &ctx.program_id,
372        ctx.accounts.mint.key,
373        extension_types,
374    )?;
375    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint])?;
376    anchor_lang::solana_program::program::get_return_data()
377        .ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
378        .and_then(|(key, data)| {
379            if key != ctx.program_id {
380                Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
381            } else {
382                data.try_into().map(u64::from_le_bytes).map_err(|_| {
383                    anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
384                })
385            }
386        })
387        .map_err(Into::into)
388}
389
390pub fn initialize_mint_close_authority<'info>(
391    ctx: CpiContext<'_, '_, '_, 'info, InitializeMintCloseAuthority<'info>>,
392    close_authority: Option<&Pubkey>,
393) -> Result<()> {
394    let ix = spl_token_2022::instruction::initialize_mint_close_authority(
395        &ctx.program_id,
396        ctx.accounts.mint.key,
397        close_authority,
398    )?;
399    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
400}
401
402pub fn initialize_immutable_owner<'info>(
403    ctx: CpiContext<'_, '_, '_, 'info, InitializeImmutableOwner<'info>>,
404) -> Result<()> {
405    let ix = spl_token_2022::instruction::initialize_immutable_owner(
406        &ctx.program_id,
407        ctx.accounts.account.key,
408    )?;
409    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
410}
411
412pub fn amount_to_ui_amount<'info>(
413    ctx: CpiContext<'_, '_, '_, 'info, AmountToUiAmount<'info>>,
414    amount: u64,
415) -> Result<String> {
416    let ix = spl_token_2022::instruction::amount_to_ui_amount(
417        &ctx.program_id,
418        ctx.accounts.account.key,
419        amount,
420    )?;
421    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
422    anchor_lang::solana_program::program::get_return_data()
423        .ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
424        .and_then(|(key, data)| {
425            if key != ctx.program_id {
426                Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
427            } else {
428                String::from_utf8(data).map_err(|_| {
429                    anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
430                })
431            }
432        })
433        .map_err(Into::into)
434}
435
436pub fn ui_amount_to_amount<'info>(
437    ctx: CpiContext<'_, '_, '_, 'info, UiAmountToAmount<'info>>,
438    ui_amount: &str,
439) -> Result<u64> {
440    let ix = spl_token_2022::instruction::ui_amount_to_amount(
441        &ctx.program_id,
442        ctx.accounts.account.key,
443        ui_amount,
444    )?;
445    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
446    anchor_lang::solana_program::program::get_return_data()
447        .ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
448        .and_then(|(key, data)| {
449            if key != ctx.program_id {
450                Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
451            } else {
452                data.try_into().map(u64::from_le_bytes).map_err(|_| {
453                    anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
454                })
455            }
456        })
457        .map_err(Into::into)
458}
459
460pub fn reallocate<'info>(
461    ctx: CpiContext<'_, '_, '_, 'info, Reallocate<'info>>,
462    extension_types: &[spl_token_2022::extension::ExtensionType],
463) -> Result<()> {
464    let ix = spl_token_2022::instruction::reallocate(
465        &ctx.program_id,
466        ctx.accounts.account.key,
467        ctx.accounts.payer.key,
468        ctx.accounts.authority.key,
469        &[],
470        extension_types,
471    )?;
472    anchor_lang::solana_program::program::invoke_signed(
473        &ix,
474        &[
475            ctx.accounts.account,
476            ctx.accounts.payer,
477            ctx.accounts.system_program,
478            ctx.accounts.authority,
479        ],
480        ctx.signer_seeds,
481    )
482    .map_err(Into::into)
483}
484
485pub fn withdraw_excess_lamports<'info>(
486    ctx: CpiContext<'_, '_, '_, 'info, WithdrawExcessLamports<'info>>,
487) -> Result<()> {
488    let ix = spl_token_2022::instruction::withdraw_excess_lamports(
489        &ctx.program_id,
490        ctx.accounts.source.key,
491        ctx.accounts.destination.key,
492        ctx.accounts.authority.key,
493        &[],
494    )?;
495    anchor_lang::solana_program::program::invoke_signed(
496        &ix,
497        &[
498            ctx.accounts.source,
499            ctx.accounts.destination,
500            ctx.accounts.authority,
501        ],
502        ctx.signer_seeds,
503    )
504    .map_err(Into::into)
505}
506
507pub fn create_native_mint<'info>(
508    ctx: CpiContext<'_, '_, '_, 'info, CreateNativeMint<'info>>,
509) -> Result<()> {
510    let ix =
511        spl_token_2022::instruction::create_native_mint(&ctx.program_id, ctx.accounts.payer.key)?;
512    anchor_lang::solana_program::program::invoke_signed(
513        &ix,
514        &[
515            ctx.accounts.payer,
516            ctx.accounts.native_mint,
517            ctx.accounts.system_program,
518        ],
519        ctx.signer_seeds,
520    )
521    .map_err(Into::into)
522}
523
524pub fn initialize_non_transferable_mint<'info>(
525    ctx: CpiContext<'_, '_, '_, 'info, InitializeNonTransferableMint<'info>>,
526) -> Result<()> {
527    let ix = spl_token_2022::instruction::initialize_non_transferable_mint(
528        &ctx.program_id,
529        ctx.accounts.mint.key,
530    )?;
531    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
532}
533
534#[derive(Accounts)]
535pub struct Transfer<'info> {
536    pub from: AccountInfo<'info>,
537    pub to: AccountInfo<'info>,
538    pub authority: AccountInfo<'info>,
539}
540
541#[derive(Accounts)]
542pub struct TransferChecked<'info> {
543    pub from: AccountInfo<'info>,
544    pub mint: AccountInfo<'info>,
545    pub to: AccountInfo<'info>,
546    pub authority: AccountInfo<'info>,
547}
548
549#[derive(Accounts)]
550pub struct MintTo<'info> {
551    pub mint: AccountInfo<'info>,
552    pub to: AccountInfo<'info>,
553    pub authority: AccountInfo<'info>,
554}
555
556#[derive(Accounts)]
557pub struct MintToChecked<'info> {
558    pub mint: AccountInfo<'info>,
559    pub to: AccountInfo<'info>,
560    pub authority: AccountInfo<'info>,
561}
562
563#[derive(Accounts)]
564pub struct Burn<'info> {
565    pub mint: AccountInfo<'info>,
566    pub from: AccountInfo<'info>,
567    pub authority: AccountInfo<'info>,
568}
569
570#[derive(Accounts)]
571pub struct BurnChecked<'info> {
572    pub mint: AccountInfo<'info>,
573    pub from: AccountInfo<'info>,
574    pub authority: AccountInfo<'info>,
575}
576
577#[derive(Accounts)]
578pub struct Approve<'info> {
579    pub to: AccountInfo<'info>,
580    pub delegate: AccountInfo<'info>,
581    pub authority: AccountInfo<'info>,
582}
583
584#[derive(Accounts)]
585pub struct ApproveChecked<'info> {
586    pub to: AccountInfo<'info>,
587    pub mint: AccountInfo<'info>,
588    pub delegate: AccountInfo<'info>,
589    pub authority: AccountInfo<'info>,
590}
591
592#[derive(Accounts)]
593pub struct Revoke<'info> {
594    pub source: AccountInfo<'info>,
595    pub authority: AccountInfo<'info>,
596}
597
598#[derive(Accounts)]
599pub struct InitializeAccount<'info> {
600    pub account: AccountInfo<'info>,
601    pub mint: AccountInfo<'info>,
602    pub authority: AccountInfo<'info>,
603    pub rent: AccountInfo<'info>,
604}
605
606#[derive(Accounts)]
607pub struct InitializeAccount3<'info> {
608    pub account: AccountInfo<'info>,
609    pub mint: AccountInfo<'info>,
610    pub authority: AccountInfo<'info>,
611}
612
613#[derive(Accounts)]
614pub struct CloseAccount<'info> {
615    pub account: AccountInfo<'info>,
616    pub destination: AccountInfo<'info>,
617    pub authority: AccountInfo<'info>,
618}
619
620#[derive(Accounts)]
621pub struct FreezeAccount<'info> {
622    pub account: AccountInfo<'info>,
623    pub mint: AccountInfo<'info>,
624    pub authority: AccountInfo<'info>,
625}
626
627#[derive(Accounts)]
628pub struct ThawAccount<'info> {
629    pub account: AccountInfo<'info>,
630    pub mint: AccountInfo<'info>,
631    pub authority: AccountInfo<'info>,
632}
633
634#[derive(Accounts)]
635pub struct InitializeMint<'info> {
636    pub mint: AccountInfo<'info>,
637    pub rent: AccountInfo<'info>,
638}
639
640#[derive(Accounts)]
641pub struct InitializeMint2<'info> {
642    pub mint: AccountInfo<'info>,
643}
644
645#[derive(Accounts)]
646pub struct SetAuthority<'info> {
647    pub current_authority: AccountInfo<'info>,
648    pub account_or_mint: AccountInfo<'info>,
649}
650
651#[derive(Accounts)]
652pub struct SyncNative<'info> {
653    pub account: AccountInfo<'info>,
654}
655
656#[derive(Accounts)]
657pub struct GetAccountDataSize<'info> {
658    pub mint: AccountInfo<'info>,
659}
660
661#[derive(Accounts)]
662pub struct InitializeMintCloseAuthority<'info> {
663    pub mint: AccountInfo<'info>,
664}
665
666#[derive(Accounts)]
667pub struct InitializeImmutableOwner<'info> {
668    pub account: AccountInfo<'info>,
669}
670
671#[derive(Accounts)]
672pub struct AmountToUiAmount<'info> {
673    pub account: AccountInfo<'info>,
674}
675
676#[derive(Accounts)]
677pub struct UiAmountToAmount<'info> {
678    pub account: AccountInfo<'info>,
679}
680
681#[derive(Accounts)]
682pub struct Reallocate<'info> {
683    pub account: AccountInfo<'info>,
684    pub payer: AccountInfo<'info>,
685    pub system_program: AccountInfo<'info>,
686    pub authority: AccountInfo<'info>,
687}
688
689#[derive(Accounts)]
690pub struct WithdrawExcessLamports<'info> {
691    pub source: AccountInfo<'info>,
692    pub destination: AccountInfo<'info>,
693    pub authority: AccountInfo<'info>,
694}
695
696#[derive(Accounts)]
697pub struct CreateNativeMint<'info> {
698    pub payer: AccountInfo<'info>,
699    pub native_mint: AccountInfo<'info>,
700    pub system_program: AccountInfo<'info>,
701}
702
703#[derive(Accounts)]
704pub struct InitializeNonTransferableMint<'info> {
705    pub mint: AccountInfo<'info>,
706}
707
708#[derive(Clone)]
709pub struct Token2022;
710
711impl anchor_lang::Id for Token2022 {
712    fn id() -> Pubkey {
713        ID
714    }
715}