Skip to main content

cronos_anchor_spl/
token.rs

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        &[], // TODO: support multisig
154    )?;
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        &[], // TODO: Support multisig signers.
176    )?;
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        &[], // TODO: Support multisig signers.
198    )?;
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        &[], // TODO: Support multisig signers.
249    )?;
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
420// Field parsers to save compute. All account validation is assumed to be done
421// outside of these methods.
422pub 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}