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
460#[derive(Accounts)]
461pub struct Transfer<'info> {
462    pub from: AccountInfo<'info>,
463    pub to: AccountInfo<'info>,
464    pub authority: AccountInfo<'info>,
465}
466
467#[derive(Accounts)]
468pub struct TransferChecked<'info> {
469    pub from: AccountInfo<'info>,
470    pub mint: AccountInfo<'info>,
471    pub to: AccountInfo<'info>,
472    pub authority: AccountInfo<'info>,
473}
474
475#[derive(Accounts)]
476pub struct MintTo<'info> {
477    pub mint: AccountInfo<'info>,
478    pub to: AccountInfo<'info>,
479    pub authority: AccountInfo<'info>,
480}
481
482#[derive(Accounts)]
483pub struct MintToChecked<'info> {
484    pub mint: AccountInfo<'info>,
485    pub to: AccountInfo<'info>,
486    pub authority: AccountInfo<'info>,
487}
488
489#[derive(Accounts)]
490pub struct Burn<'info> {
491    pub mint: AccountInfo<'info>,
492    pub from: AccountInfo<'info>,
493    pub authority: AccountInfo<'info>,
494}
495
496#[derive(Accounts)]
497pub struct BurnChecked<'info> {
498    pub mint: AccountInfo<'info>,
499    pub from: AccountInfo<'info>,
500    pub authority: AccountInfo<'info>,
501}
502
503#[derive(Accounts)]
504pub struct Approve<'info> {
505    pub to: AccountInfo<'info>,
506    pub delegate: AccountInfo<'info>,
507    pub authority: AccountInfo<'info>,
508}
509
510#[derive(Accounts)]
511pub struct ApproveChecked<'info> {
512    pub to: AccountInfo<'info>,
513    pub mint: AccountInfo<'info>,
514    pub delegate: AccountInfo<'info>,
515    pub authority: AccountInfo<'info>,
516}
517
518#[derive(Accounts)]
519pub struct Revoke<'info> {
520    pub source: AccountInfo<'info>,
521    pub authority: AccountInfo<'info>,
522}
523
524#[derive(Accounts)]
525pub struct InitializeAccount<'info> {
526    pub account: AccountInfo<'info>,
527    pub mint: AccountInfo<'info>,
528    pub authority: AccountInfo<'info>,
529    pub rent: AccountInfo<'info>,
530}
531
532#[derive(Accounts)]
533pub struct InitializeAccount3<'info> {
534    pub account: AccountInfo<'info>,
535    pub mint: AccountInfo<'info>,
536    pub authority: AccountInfo<'info>,
537}
538
539#[derive(Accounts)]
540pub struct CloseAccount<'info> {
541    pub account: AccountInfo<'info>,
542    pub destination: AccountInfo<'info>,
543    pub authority: AccountInfo<'info>,
544}
545
546#[derive(Accounts)]
547pub struct FreezeAccount<'info> {
548    pub account: AccountInfo<'info>,
549    pub mint: AccountInfo<'info>,
550    pub authority: AccountInfo<'info>,
551}
552
553#[derive(Accounts)]
554pub struct ThawAccount<'info> {
555    pub account: AccountInfo<'info>,
556    pub mint: AccountInfo<'info>,
557    pub authority: AccountInfo<'info>,
558}
559
560#[derive(Accounts)]
561pub struct InitializeMint<'info> {
562    pub mint: AccountInfo<'info>,
563    pub rent: AccountInfo<'info>,
564}
565
566#[derive(Accounts)]
567pub struct InitializeMint2<'info> {
568    pub mint: AccountInfo<'info>,
569}
570
571#[derive(Accounts)]
572pub struct SetAuthority<'info> {
573    pub current_authority: AccountInfo<'info>,
574    pub account_or_mint: AccountInfo<'info>,
575}
576
577#[derive(Accounts)]
578pub struct SyncNative<'info> {
579    pub account: AccountInfo<'info>,
580}
581
582#[derive(Accounts)]
583pub struct GetAccountDataSize<'info> {
584    pub mint: AccountInfo<'info>,
585}
586
587#[derive(Accounts)]
588pub struct InitializeMintCloseAuthority<'info> {
589    pub mint: AccountInfo<'info>,
590}
591
592#[derive(Accounts)]
593pub struct InitializeImmutableOwner<'info> {
594    pub account: AccountInfo<'info>,
595}
596
597#[derive(Accounts)]
598pub struct AmountToUiAmount<'info> {
599    pub account: AccountInfo<'info>,
600}
601
602#[derive(Accounts)]
603pub struct UiAmountToAmount<'info> {
604    pub account: AccountInfo<'info>,
605}
606
607#[derive(Clone)]
608pub struct Token2022;
609
610impl anchor_lang::Id for Token2022 {
611    fn id() -> Pubkey {
612        ID
613    }
614}