gpl_token/
instruction.rs

1//! Instruction types
2
3use crate::{check_program_account, error::TokenError};
4use gemachain_program::{
5    instruction::{AccountMeta, Instruction},
6    program_error::ProgramError,
7    program_option::COption,
8    pubkey::Pubkey,
9    sysvar,
10};
11use std::convert::TryInto;
12use std::mem::size_of;
13
14/// Minimum number of multisignature signers (min N)
15pub const MIN_SIGNERS: usize = 1;
16/// Maximum number of multisignature signers (max N)
17pub const MAX_SIGNERS: usize = 11;
18
19/// Instructions supported by the token program.
20#[repr(C)]
21#[derive(Clone, Debug, PartialEq)]
22pub enum TokenInstruction {
23    /// Initializes a new mint and optionally deposits all the newly minted
24    /// tokens in an account.
25    ///
26    /// The `InitializeMint` instruction requires no signers and MUST be
27    /// included within the same Transaction as the system program's
28    /// `CreateAccount` instruction that creates the account being initialized.
29    /// Otherwise another party can acquire ownership of the uninitialized
30    /// account.
31    ///
32    /// Accounts expected by this instruction:
33    ///
34    ///   0. `[writable]` The mint to initialize.
35    ///   1. `[]` Rent sysvar
36    ///
37    InitializeMint {
38        /// Number of base 10 digits to the right of the decimal place.
39        decimals: u8,
40        /// The authority/multisignature to mint tokens.
41        mint_authority: Pubkey,
42        /// The freeze authority/multisignature of the mint.
43        freeze_authority: COption<Pubkey>,
44    },
45    /// Initializes a new account to hold tokens.  If this account is associated
46    /// with the native mint then the token balance of the initialized account
47    /// will be equal to the amount of GEMA in the account. If this account is
48    /// associated with another mint, that mint must be initialized before this
49    /// command can succeed.
50    ///
51    /// The `InitializeAccount` instruction requires no signers and MUST be
52    /// included within the same Transaction as the system program's
53    /// `CreateAccount` instruction that creates the account being initialized.
54    /// Otherwise another party can acquire ownership of the uninitialized
55    /// account.
56    ///
57    /// Accounts expected by this instruction:
58    ///
59    ///   0. `[writable]`  The account to initialize.
60    ///   1. `[]` The mint this account will be associated with.
61    ///   2. `[]` The new account's owner/multisignature.
62    ///   3. `[]` Rent sysvar
63    InitializeAccount,
64    /// Initializes a multisignature account with N provided signers.
65    ///
66    /// Multisignature accounts can used in place of any single owner/delegate
67    /// accounts in any token instruction that require an owner/delegate to be
68    /// present.  The variant field represents the number of signers (M)
69    /// required to validate this multisignature account.
70    ///
71    /// The `InitializeMultisig` instruction requires no signers and MUST be
72    /// included within the same Transaction as the system program's
73    /// `CreateAccount` instruction that creates the account being initialized.
74    /// Otherwise another party can acquire ownership of the uninitialized
75    /// account.
76    ///
77    /// Accounts expected by this instruction:
78    ///
79    ///   0. `[writable]` The multisignature account to initialize.
80    ///   1. `[]` Rent sysvar
81    ///   2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <=
82    ///      11.
83    InitializeMultisig {
84        /// The number of signers (M) required to validate this multisignature
85        /// account.
86        m: u8,
87    },
88    /// Transfers tokens from one account to another either directly or via a
89    /// delegate.  If this account is associated with the native mint then equal
90    /// amounts of GEMA and Tokens will be transferred to the destination
91    /// account.
92    ///
93    /// Accounts expected by this instruction:
94    ///
95    ///   * Single owner/delegate
96    ///   0. `[writable]` The source account.
97    ///   1. `[writable]` The destination account.
98    ///   2. `[signer]` The source account's owner/delegate.
99    ///
100    ///   * Multisignature owner/delegate
101    ///   0. `[writable]` The source account.
102    ///   1. `[writable]` The destination account.
103    ///   2. `[]` The source account's multisignature owner/delegate.
104    ///   3. ..3+M `[signer]` M signer accounts.
105    Transfer {
106        /// The amount of tokens to transfer.
107        amount: u64,
108    },
109    /// Approves a delegate.  A delegate is given the authority over tokens on
110    /// behalf of the source account's owner.
111    ///
112    /// Accounts expected by this instruction:
113    ///
114    ///   * Single owner
115    ///   0. `[writable]` The source account.
116    ///   1. `[]` The delegate.
117    ///   2. `[signer]` The source account owner.
118    ///
119    ///   * Multisignature owner
120    ///   0. `[writable]` The source account.
121    ///   1. `[]` The delegate.
122    ///   2. `[]` The source account's multisignature owner.
123    ///   3. ..3+M `[signer]` M signer accounts
124    Approve {
125        /// The amount of tokens the delegate is approved for.
126        amount: u64,
127    },
128    /// Revokes the delegate's authority.
129    ///
130    /// Accounts expected by this instruction:
131    ///
132    ///   * Single owner
133    ///   0. `[writable]` The source account.
134    ///   1. `[signer]` The source account owner.
135    ///
136    ///   * Multisignature owner
137    ///   0. `[writable]` The source account.
138    ///   1. `[]` The source account's multisignature owner.
139    ///   2. ..2+M `[signer]` M signer accounts
140    Revoke,
141    /// Sets a new authority of a mint or account.
142    ///
143    /// Accounts expected by this instruction:
144    ///
145    ///   * Single authority
146    ///   0. `[writable]` The mint or account to change the authority of.
147    ///   1. `[signer]` The current authority of the mint or account.
148    ///
149    ///   * Multisignature authority
150    ///   0. `[writable]` The mint or account to change the authority of.
151    ///   1. `[]` The mint's or account's current multisignature authority.
152    ///   2. ..2+M `[signer]` M signer accounts
153    SetAuthority {
154        /// The type of authority to update.
155        authority_type: AuthorityType,
156        /// The new authority
157        new_authority: COption<Pubkey>,
158    },
159    /// Mints new tokens to an account.  The native mint does not support
160    /// minting.
161    ///
162    /// Accounts expected by this instruction:
163    ///
164    ///   * Single authority
165    ///   0. `[writable]` The mint.
166    ///   1. `[writable]` The account to mint tokens to.
167    ///   2. `[signer]` The mint's minting authority.
168    ///
169    ///   * Multisignature authority
170    ///   0. `[writable]` The mint.
171    ///   1. `[writable]` The account to mint tokens to.
172    ///   2. `[]` The mint's multisignature mint-tokens authority.
173    ///   3. ..3+M `[signer]` M signer accounts.
174    MintTo {
175        /// The amount of new tokens to mint.
176        amount: u64,
177    },
178    /// Burns tokens by removing them from an account.  `Burn` does not support
179    /// accounts associated with the native mint, use `CloseAccount` instead.
180    ///
181    /// Accounts expected by this instruction:
182    ///
183    ///   * Single owner/delegate
184    ///   0. `[writable]` The account to burn from.
185    ///   1. `[writable]` The token mint.
186    ///   2. `[signer]` The account's owner/delegate.
187    ///
188    ///   * Multisignature owner/delegate
189    ///   0. `[writable]` The account to burn from.
190    ///   1. `[writable]` The token mint.
191    ///   2. `[]` The account's multisignature owner/delegate.
192    ///   3. ..3+M `[signer]` M signer accounts.
193    Burn {
194        /// The amount of tokens to burn.
195        amount: u64,
196    },
197    /// Close an account by transferring all its GEMA to the destination account.
198    /// Non-native accounts may only be closed if its token amount is zero.
199    ///
200    /// Accounts expected by this instruction:
201    ///
202    ///   * Single owner
203    ///   0. `[writable]` The account to close.
204    ///   1. `[writable]` The destination account.
205    ///   2. `[signer]` The account's owner.
206    ///
207    ///   * Multisignature owner
208    ///   0. `[writable]` The account to close.
209    ///   1. `[writable]` The destination account.
210    ///   2. `[]` The account's multisignature owner.
211    ///   3. ..3+M `[signer]` M signer accounts.
212    CloseAccount,
213    /// Freeze an Initialized account using the Mint's freeze_authority (if
214    /// set).
215    ///
216    /// Accounts expected by this instruction:
217    ///
218    ///   * Single owner
219    ///   0. `[writable]` The account to freeze.
220    ///   1. `[]` The token mint.
221    ///   2. `[signer]` The mint freeze authority.
222    ///
223    ///   * Multisignature owner
224    ///   0. `[writable]` The account to freeze.
225    ///   1. `[]` The token mint.
226    ///   2. `[]` The mint's multisignature freeze authority.
227    ///   3. ..3+M `[signer]` M signer accounts.
228    FreezeAccount,
229    /// Thaw a Frozen account using the Mint's freeze_authority (if set).
230    ///
231    /// Accounts expected by this instruction:
232    ///
233    ///   * Single owner
234    ///   0. `[writable]` The account to freeze.
235    ///   1. `[]` The token mint.
236    ///   2. `[signer]` The mint freeze authority.
237    ///
238    ///   * Multisignature owner
239    ///   0. `[writable]` The account to freeze.
240    ///   1. `[]` The token mint.
241    ///   2. `[]` The mint's multisignature freeze authority.
242    ///   3. ..3+M `[signer]` M signer accounts.
243    ThawAccount,
244
245    /// Transfers tokens from one account to another either directly or via a
246    /// delegate.  If this account is associated with the native mint then equal
247    /// amounts of GEMA and Tokens will be transferred to the destination
248    /// account.
249    ///
250    /// This instruction differs from Transfer in that the token mint and
251    /// decimals value is checked by the caller.  This may be useful when
252    /// creating transactions offline or within a hardware wallet.
253    ///
254    /// Accounts expected by this instruction:
255    ///
256    ///   * Single owner/delegate
257    ///   0. `[writable]` The source account.
258    ///   1. `[]` The token mint.
259    ///   2. `[writable]` The destination account.
260    ///   3. `[signer]` The source account's owner/delegate.
261    ///
262    ///   * Multisignature owner/delegate
263    ///   0. `[writable]` The source account.
264    ///   1. `[]` The token mint.
265    ///   2. `[writable]` The destination account.
266    ///   3. `[]` The source account's multisignature owner/delegate.
267    ///   4. ..4+M `[signer]` M signer accounts.
268    TransferChecked {
269        /// The amount of tokens to transfer.
270        amount: u64,
271        /// Expected number of base 10 digits to the right of the decimal place.
272        decimals: u8,
273    },
274    /// Approves a delegate.  A delegate is given the authority over tokens on
275    /// behalf of the source account's owner.
276    ///
277    /// This instruction differs from Approve in that the token mint and
278    /// decimals value is checked by the caller.  This may be useful when
279    /// creating transactions offline or within a hardware wallet.
280    ///
281    /// Accounts expected by this instruction:
282    ///
283    ///   * Single owner
284    ///   0. `[writable]` The source account.
285    ///   1. `[]` The token mint.
286    ///   2. `[]` The delegate.
287    ///   3. `[signer]` The source account owner.
288    ///
289    ///   * Multisignature owner
290    ///   0. `[writable]` The source account.
291    ///   1. `[]` The token mint.
292    ///   2. `[]` The delegate.
293    ///   3. `[]` The source account's multisignature owner.
294    ///   4. ..4+M `[signer]` M signer accounts
295    ApproveChecked {
296        /// The amount of tokens the delegate is approved for.
297        amount: u64,
298        /// Expected number of base 10 digits to the right of the decimal place.
299        decimals: u8,
300    },
301    /// Mints new tokens to an account.  The native mint does not support
302    /// minting.
303    ///
304    /// This instruction differs from MintTo in that the decimals value is
305    /// checked by the caller.  This may be useful when creating transactions
306    /// offline or within a hardware wallet.
307    ///
308    /// Accounts expected by this instruction:
309    ///
310    ///   * Single authority
311    ///   0. `[writable]` The mint.
312    ///   1. `[writable]` The account to mint tokens to.
313    ///   2. `[signer]` The mint's minting authority.
314    ///
315    ///   * Multisignature authority
316    ///   0. `[writable]` The mint.
317    ///   1. `[writable]` The account to mint tokens to.
318    ///   2. `[]` The mint's multisignature mint-tokens authority.
319    ///   3. ..3+M `[signer]` M signer accounts.
320    MintToChecked {
321        /// The amount of new tokens to mint.
322        amount: u64,
323        /// Expected number of base 10 digits to the right of the decimal place.
324        decimals: u8,
325    },
326    /// Burns tokens by removing them from an account.  `BurnChecked` does not
327    /// support accounts associated with the native mint, use `CloseAccount`
328    /// instead.
329    ///
330    /// This instruction differs from Burn in that the decimals value is checked
331    /// by the caller. This may be useful when creating transactions offline or
332    /// within a hardware wallet.
333    ///
334    /// Accounts expected by this instruction:
335    ///
336    ///   * Single owner/delegate
337    ///   0. `[writable]` The account to burn from.
338    ///   1. `[writable]` The token mint.
339    ///   2. `[signer]` The account's owner/delegate.
340    ///
341    ///   * Multisignature owner/delegate
342    ///   0. `[writable]` The account to burn from.
343    ///   1. `[writable]` The token mint.
344    ///   2. `[]` The account's multisignature owner/delegate.
345    ///   3. ..3+M `[signer]` M signer accounts.
346    BurnChecked {
347        /// The amount of tokens to burn.
348        amount: u64,
349        /// Expected number of base 10 digits to the right of the decimal place.
350        decimals: u8,
351    },
352    /// Like InitializeAccount, but the owner pubkey is passed via instruction data
353    /// rather than the accounts list. This variant may be preferable when using
354    /// Cross Program Invocation from an instruction that does not need the owner's
355    /// `AccountInfo` otherwise.
356    ///
357    /// Accounts expected by this instruction:
358    ///
359    ///   0. `[writable]`  The account to initialize.
360    ///   1. `[]` The mint this account will be associated with.
361    ///   3. `[]` Rent sysvar
362    InitializeAccount2 {
363        /// The new account's owner/multisignature.
364        owner: Pubkey,
365    },
366    /// Given a wrapped / native token account (a token account containing GEMA)
367    /// updates its amount field based on the account's underlying `carats`.
368    /// This is useful if a non-wrapped GEMA account uses `system_instruction::transfer`
369    /// to move carats to a wrapped token account, and needs to have its token
370    /// `amount` field updated.
371    ///
372    /// Accounts expected by this instruction:
373    ///
374    ///   0. `[writable]`  The native token account to sync with its underlying carats.
375    SyncNative,
376    /// Like InitializeAccount2, but does not require the Rent sysvar to be provided
377    ///
378    /// Accounts expected by this instruction:
379    ///
380    ///   0. `[writable]`  The account to initialize.
381    ///   1. `[]` The mint this account will be associated with.
382    InitializeAccount3 {
383        /// The new account's owner/multisignature.
384        owner: Pubkey,
385    },
386    /// Like InitializeMultisig, but does not require the Rent sysvar to be provided
387    ///
388    /// Accounts expected by this instruction:
389    ///
390    ///   0. `[writable]` The multisignature account to initialize.
391    ///   1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <=
392    ///      11.
393    InitializeMultisig2 {
394        /// The number of signers (M) required to validate this multisignature
395        /// account.
396        m: u8,
397    },
398    /// Like InitializeMint, but does not require the Rent sysvar to be provided
399    ///
400    /// Accounts expected by this instruction:
401    ///
402    ///   0. `[writable]` The mint to initialize.
403    ///
404    InitializeMint2 {
405        /// Number of base 10 digits to the right of the decimal place.
406        decimals: u8,
407        /// The authority/multisignature to mint tokens.
408        mint_authority: Pubkey,
409        /// The freeze authority/multisignature of the mint.
410        freeze_authority: COption<Pubkey>,
411    },
412}
413impl TokenInstruction {
414    /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
415    pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
416        use TokenError::InvalidInstruction;
417
418        let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
419        Ok(match tag {
420            0 => {
421                let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
422                let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
423                let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
424                Self::InitializeMint {
425                    mint_authority,
426                    freeze_authority,
427                    decimals,
428                }
429            }
430            1 => Self::InitializeAccount,
431            2 => {
432                let &m = rest.get(0).ok_or(InvalidInstruction)?;
433                Self::InitializeMultisig { m }
434            }
435            3 | 4 | 7 | 8 => {
436                let amount = rest
437                    .get(..8)
438                    .and_then(|slice| slice.try_into().ok())
439                    .map(u64::from_le_bytes)
440                    .ok_or(InvalidInstruction)?;
441                match tag {
442                    3 => Self::Transfer { amount },
443                    4 => Self::Approve { amount },
444                    7 => Self::MintTo { amount },
445                    8 => Self::Burn { amount },
446                    _ => unreachable!(),
447                }
448            }
449            5 => Self::Revoke,
450            6 => {
451                let (authority_type, rest) = rest
452                    .split_first()
453                    .ok_or_else(|| ProgramError::from(InvalidInstruction))
454                    .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
455                let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
456
457                Self::SetAuthority {
458                    authority_type,
459                    new_authority,
460                }
461            }
462            9 => Self::CloseAccount,
463            10 => Self::FreezeAccount,
464            11 => Self::ThawAccount,
465            12 => {
466                let (amount, rest) = rest.split_at(8);
467                let amount = amount
468                    .try_into()
469                    .ok()
470                    .map(u64::from_le_bytes)
471                    .ok_or(InvalidInstruction)?;
472                let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
473
474                Self::TransferChecked { amount, decimals }
475            }
476            13 => {
477                let (amount, rest) = rest.split_at(8);
478                let amount = amount
479                    .try_into()
480                    .ok()
481                    .map(u64::from_le_bytes)
482                    .ok_or(InvalidInstruction)?;
483                let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
484
485                Self::ApproveChecked { amount, decimals }
486            }
487            14 => {
488                let (amount, rest) = rest.split_at(8);
489                let amount = amount
490                    .try_into()
491                    .ok()
492                    .map(u64::from_le_bytes)
493                    .ok_or(InvalidInstruction)?;
494                let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
495
496                Self::MintToChecked { amount, decimals }
497            }
498            15 => {
499                let (amount, rest) = rest.split_at(8);
500                let amount = amount
501                    .try_into()
502                    .ok()
503                    .map(u64::from_le_bytes)
504                    .ok_or(InvalidInstruction)?;
505                let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
506
507                Self::BurnChecked { amount, decimals }
508            }
509            16 => {
510                let (owner, _rest) = Self::unpack_pubkey(rest)?;
511                Self::InitializeAccount2 { owner }
512            }
513            17 => Self::SyncNative,
514            18 => {
515                let (owner, _rest) = Self::unpack_pubkey(rest)?;
516                Self::InitializeAccount3 { owner }
517            }
518            19 => {
519                let &m = rest.get(0).ok_or(InvalidInstruction)?;
520                Self::InitializeMultisig2 { m }
521            }
522            20 => {
523                let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
524                let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
525                let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
526                Self::InitializeMint2 {
527                    mint_authority,
528                    freeze_authority,
529                    decimals,
530                }
531            }
532            _ => return Err(TokenError::InvalidInstruction.into()),
533        })
534    }
535
536    /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
537    pub fn pack(&self) -> Vec<u8> {
538        let mut buf = Vec::with_capacity(size_of::<Self>());
539        match self {
540            &Self::InitializeMint {
541                ref mint_authority,
542                ref freeze_authority,
543                decimals,
544            } => {
545                buf.push(0);
546                buf.push(decimals);
547                buf.extend_from_slice(mint_authority.as_ref());
548                Self::pack_pubkey_option(freeze_authority, &mut buf);
549            }
550            Self::InitializeAccount => buf.push(1),
551            &Self::InitializeMultisig { m } => {
552                buf.push(2);
553                buf.push(m);
554            }
555            &Self::Transfer { amount } => {
556                buf.push(3);
557                buf.extend_from_slice(&amount.to_le_bytes());
558            }
559            &Self::Approve { amount } => {
560                buf.push(4);
561                buf.extend_from_slice(&amount.to_le_bytes());
562            }
563            &Self::MintTo { amount } => {
564                buf.push(7);
565                buf.extend_from_slice(&amount.to_le_bytes());
566            }
567            &Self::Burn { amount } => {
568                buf.push(8);
569                buf.extend_from_slice(&amount.to_le_bytes());
570            }
571            Self::Revoke => buf.push(5),
572            Self::SetAuthority {
573                authority_type,
574                ref new_authority,
575            } => {
576                buf.push(6);
577                buf.push(authority_type.into());
578                Self::pack_pubkey_option(new_authority, &mut buf);
579            }
580            Self::CloseAccount => buf.push(9),
581            Self::FreezeAccount => buf.push(10),
582            Self::ThawAccount => buf.push(11),
583            &Self::TransferChecked { amount, decimals } => {
584                buf.push(12);
585                buf.extend_from_slice(&amount.to_le_bytes());
586                buf.push(decimals);
587            }
588            &Self::ApproveChecked { amount, decimals } => {
589                buf.push(13);
590                buf.extend_from_slice(&amount.to_le_bytes());
591                buf.push(decimals);
592            }
593            &Self::MintToChecked { amount, decimals } => {
594                buf.push(14);
595                buf.extend_from_slice(&amount.to_le_bytes());
596                buf.push(decimals);
597            }
598            &Self::BurnChecked { amount, decimals } => {
599                buf.push(15);
600                buf.extend_from_slice(&amount.to_le_bytes());
601                buf.push(decimals);
602            }
603            &Self::InitializeAccount2 { owner } => {
604                buf.push(16);
605                buf.extend_from_slice(owner.as_ref());
606            }
607            &Self::SyncNative => {
608                buf.push(17);
609            }
610            &Self::InitializeAccount3 { owner } => {
611                buf.push(18);
612                buf.extend_from_slice(owner.as_ref());
613            }
614            &Self::InitializeMultisig2 { m } => {
615                buf.push(19);
616                buf.push(m);
617            }
618            &Self::InitializeMint2 {
619                ref mint_authority,
620                ref freeze_authority,
621                decimals,
622            } => {
623                buf.push(20);
624                buf.push(decimals);
625                buf.extend_from_slice(mint_authority.as_ref());
626                Self::pack_pubkey_option(freeze_authority, &mut buf);
627            }
628        };
629        buf
630    }
631
632    fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
633        if input.len() >= 32 {
634            let (key, rest) = input.split_at(32);
635            let pk = Pubkey::new(key);
636            Ok((pk, rest))
637        } else {
638            Err(TokenError::InvalidInstruction.into())
639        }
640    }
641
642    fn unpack_pubkey_option(input: &[u8]) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
643        match input.split_first() {
644            Option::Some((&0, rest)) => Ok((COption::None, rest)),
645            Option::Some((&1, rest)) if rest.len() >= 32 => {
646                let (key, rest) = rest.split_at(32);
647                let pk = Pubkey::new(key);
648                Ok((COption::Some(pk), rest))
649            }
650            _ => Err(TokenError::InvalidInstruction.into()),
651        }
652    }
653
654    fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
655        match *value {
656            COption::Some(ref key) => {
657                buf.push(1);
658                buf.extend_from_slice(&key.to_bytes());
659            }
660            COption::None => buf.push(0),
661        }
662    }
663}
664
665/// Specifies the authority type for SetAuthority instructions
666#[repr(u8)]
667#[derive(Clone, Debug, PartialEq)]
668pub enum AuthorityType {
669    /// Authority to mint new tokens
670    MintTokens,
671    /// Authority to freeze any account associated with the Mint
672    FreezeAccount,
673    /// Owner of a given token account
674    AccountOwner,
675    /// Authority to close a token account
676    CloseAccount,
677}
678
679impl AuthorityType {
680    fn into(&self) -> u8 {
681        match self {
682            AuthorityType::MintTokens => 0,
683            AuthorityType::FreezeAccount => 1,
684            AuthorityType::AccountOwner => 2,
685            AuthorityType::CloseAccount => 3,
686        }
687    }
688
689    fn from(index: u8) -> Result<Self, ProgramError> {
690        match index {
691            0 => Ok(AuthorityType::MintTokens),
692            1 => Ok(AuthorityType::FreezeAccount),
693            2 => Ok(AuthorityType::AccountOwner),
694            3 => Ok(AuthorityType::CloseAccount),
695            _ => Err(TokenError::InvalidInstruction.into()),
696        }
697    }
698}
699
700/// Creates a `InitializeMint` instruction.
701pub fn initialize_mint(
702    token_program_id: &Pubkey,
703    mint_pubkey: &Pubkey,
704    mint_authority_pubkey: &Pubkey,
705    freeze_authority_pubkey: Option<&Pubkey>,
706    decimals: u8,
707) -> Result<Instruction, ProgramError> {
708    check_program_account(token_program_id)?;
709    let freeze_authority = freeze_authority_pubkey.cloned().into();
710    let data = TokenInstruction::InitializeMint {
711        mint_authority: *mint_authority_pubkey,
712        freeze_authority,
713        decimals,
714    }
715    .pack();
716
717    let accounts = vec![
718        AccountMeta::new(*mint_pubkey, false),
719        AccountMeta::new_readonly(sysvar::rent::id(), false),
720    ];
721
722    Ok(Instruction {
723        program_id: *token_program_id,
724        accounts,
725        data,
726    })
727}
728
729/// Creates a `InitializeMint2` instruction.
730pub fn initialize_mint2(
731    token_program_id: &Pubkey,
732    mint_pubkey: &Pubkey,
733    mint_authority_pubkey: &Pubkey,
734    freeze_authority_pubkey: Option<&Pubkey>,
735    decimals: u8,
736) -> Result<Instruction, ProgramError> {
737    check_program_account(token_program_id)?;
738    let freeze_authority = freeze_authority_pubkey.cloned().into();
739    let data = TokenInstruction::InitializeMint2 {
740        mint_authority: *mint_authority_pubkey,
741        freeze_authority,
742        decimals,
743    }
744    .pack();
745
746    let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
747
748    Ok(Instruction {
749        program_id: *token_program_id,
750        accounts,
751        data,
752    })
753}
754
755/// Creates a `InitializeAccount` instruction.
756pub fn initialize_account(
757    token_program_id: &Pubkey,
758    account_pubkey: &Pubkey,
759    mint_pubkey: &Pubkey,
760    owner_pubkey: &Pubkey,
761) -> Result<Instruction, ProgramError> {
762    check_program_account(token_program_id)?;
763    let data = TokenInstruction::InitializeAccount.pack();
764
765    let accounts = vec![
766        AccountMeta::new(*account_pubkey, false),
767        AccountMeta::new_readonly(*mint_pubkey, false),
768        AccountMeta::new_readonly(*owner_pubkey, false),
769        AccountMeta::new_readonly(sysvar::rent::id(), false),
770    ];
771
772    Ok(Instruction {
773        program_id: *token_program_id,
774        accounts,
775        data,
776    })
777}
778
779/// Creates a `InitializeAccount2` instruction.
780pub fn initialize_account2(
781    token_program_id: &Pubkey,
782    account_pubkey: &Pubkey,
783    mint_pubkey: &Pubkey,
784    owner_pubkey: &Pubkey,
785) -> Result<Instruction, ProgramError> {
786    check_program_account(token_program_id)?;
787    let data = TokenInstruction::InitializeAccount2 {
788        owner: *owner_pubkey,
789    }
790    .pack();
791
792    let accounts = vec![
793        AccountMeta::new(*account_pubkey, false),
794        AccountMeta::new_readonly(*mint_pubkey, false),
795        AccountMeta::new_readonly(sysvar::rent::id(), false),
796    ];
797
798    Ok(Instruction {
799        program_id: *token_program_id,
800        accounts,
801        data,
802    })
803}
804
805/// Creates a `InitializeAccount3` instruction.
806pub fn initialize_account3(
807    token_program_id: &Pubkey,
808    account_pubkey: &Pubkey,
809    mint_pubkey: &Pubkey,
810    owner_pubkey: &Pubkey,
811) -> Result<Instruction, ProgramError> {
812    check_program_account(token_program_id)?;
813    let data = TokenInstruction::InitializeAccount3 {
814        owner: *owner_pubkey,
815    }
816    .pack();
817
818    let accounts = vec![
819        AccountMeta::new(*account_pubkey, false),
820        AccountMeta::new_readonly(*mint_pubkey, false),
821    ];
822
823    Ok(Instruction {
824        program_id: *token_program_id,
825        accounts,
826        data,
827    })
828}
829
830/// Creates a `InitializeMultisig` instruction.
831pub fn initialize_multisig(
832    token_program_id: &Pubkey,
833    multisig_pubkey: &Pubkey,
834    signer_pubkeys: &[&Pubkey],
835    m: u8,
836) -> Result<Instruction, ProgramError> {
837    check_program_account(token_program_id)?;
838    if !is_valid_signer_index(m as usize)
839        || !is_valid_signer_index(signer_pubkeys.len())
840        || m as usize > signer_pubkeys.len()
841    {
842        return Err(ProgramError::MissingRequiredSignature);
843    }
844    let data = TokenInstruction::InitializeMultisig { m }.pack();
845
846    let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
847    accounts.push(AccountMeta::new(*multisig_pubkey, false));
848    accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
849    for signer_pubkey in signer_pubkeys.iter() {
850        accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
851    }
852
853    Ok(Instruction {
854        program_id: *token_program_id,
855        accounts,
856        data,
857    })
858}
859
860/// Creates a `InitializeMultisig2` instruction.
861pub fn initialize_multisig2(
862    token_program_id: &Pubkey,
863    multisig_pubkey: &Pubkey,
864    signer_pubkeys: &[&Pubkey],
865    m: u8,
866) -> Result<Instruction, ProgramError> {
867    check_program_account(token_program_id)?;
868    if !is_valid_signer_index(m as usize)
869        || !is_valid_signer_index(signer_pubkeys.len())
870        || m as usize > signer_pubkeys.len()
871    {
872        return Err(ProgramError::MissingRequiredSignature);
873    }
874    let data = TokenInstruction::InitializeMultisig2 { m }.pack();
875
876    let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
877    accounts.push(AccountMeta::new(*multisig_pubkey, false));
878    for signer_pubkey in signer_pubkeys.iter() {
879        accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
880    }
881
882    Ok(Instruction {
883        program_id: *token_program_id,
884        accounts,
885        data,
886    })
887}
888
889/// Creates a `Transfer` instruction.
890pub fn transfer(
891    token_program_id: &Pubkey,
892    source_pubkey: &Pubkey,
893    destination_pubkey: &Pubkey,
894    authority_pubkey: &Pubkey,
895    signer_pubkeys: &[&Pubkey],
896    amount: u64,
897) -> Result<Instruction, ProgramError> {
898    check_program_account(token_program_id)?;
899    let data = TokenInstruction::Transfer { amount }.pack();
900
901    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
902    accounts.push(AccountMeta::new(*source_pubkey, false));
903    accounts.push(AccountMeta::new(*destination_pubkey, false));
904    accounts.push(AccountMeta::new_readonly(
905        *authority_pubkey,
906        signer_pubkeys.is_empty(),
907    ));
908    for signer_pubkey in signer_pubkeys.iter() {
909        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
910    }
911
912    Ok(Instruction {
913        program_id: *token_program_id,
914        accounts,
915        data,
916    })
917}
918
919/// Creates an `Approve` instruction.
920pub fn approve(
921    token_program_id: &Pubkey,
922    source_pubkey: &Pubkey,
923    delegate_pubkey: &Pubkey,
924    owner_pubkey: &Pubkey,
925    signer_pubkeys: &[&Pubkey],
926    amount: u64,
927) -> Result<Instruction, ProgramError> {
928    check_program_account(token_program_id)?;
929    let data = TokenInstruction::Approve { amount }.pack();
930
931    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
932    accounts.push(AccountMeta::new(*source_pubkey, false));
933    accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
934    accounts.push(AccountMeta::new_readonly(
935        *owner_pubkey,
936        signer_pubkeys.is_empty(),
937    ));
938    for signer_pubkey in signer_pubkeys.iter() {
939        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
940    }
941
942    Ok(Instruction {
943        program_id: *token_program_id,
944        accounts,
945        data,
946    })
947}
948
949/// Creates a `Revoke` instruction.
950pub fn revoke(
951    token_program_id: &Pubkey,
952    source_pubkey: &Pubkey,
953    owner_pubkey: &Pubkey,
954    signer_pubkeys: &[&Pubkey],
955) -> Result<Instruction, ProgramError> {
956    check_program_account(token_program_id)?;
957    let data = TokenInstruction::Revoke.pack();
958
959    let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
960    accounts.push(AccountMeta::new(*source_pubkey, false));
961    accounts.push(AccountMeta::new_readonly(
962        *owner_pubkey,
963        signer_pubkeys.is_empty(),
964    ));
965    for signer_pubkey in signer_pubkeys.iter() {
966        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
967    }
968
969    Ok(Instruction {
970        program_id: *token_program_id,
971        accounts,
972        data,
973    })
974}
975
976/// Creates a `SetAuthority` instruction.
977pub fn set_authority(
978    token_program_id: &Pubkey,
979    owned_pubkey: &Pubkey,
980    new_authority_pubkey: Option<&Pubkey>,
981    authority_type: AuthorityType,
982    owner_pubkey: &Pubkey,
983    signer_pubkeys: &[&Pubkey],
984) -> Result<Instruction, ProgramError> {
985    check_program_account(token_program_id)?;
986    let new_authority = new_authority_pubkey.cloned().into();
987    let data = TokenInstruction::SetAuthority {
988        authority_type,
989        new_authority,
990    }
991    .pack();
992
993    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
994    accounts.push(AccountMeta::new(*owned_pubkey, false));
995    accounts.push(AccountMeta::new_readonly(
996        *owner_pubkey,
997        signer_pubkeys.is_empty(),
998    ));
999    for signer_pubkey in signer_pubkeys.iter() {
1000        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1001    }
1002
1003    Ok(Instruction {
1004        program_id: *token_program_id,
1005        accounts,
1006        data,
1007    })
1008}
1009
1010/// Creates a `MintTo` instruction.
1011pub fn mint_to(
1012    token_program_id: &Pubkey,
1013    mint_pubkey: &Pubkey,
1014    account_pubkey: &Pubkey,
1015    owner_pubkey: &Pubkey,
1016    signer_pubkeys: &[&Pubkey],
1017    amount: u64,
1018) -> Result<Instruction, ProgramError> {
1019    check_program_account(token_program_id)?;
1020    let data = TokenInstruction::MintTo { amount }.pack();
1021
1022    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1023    accounts.push(AccountMeta::new(*mint_pubkey, false));
1024    accounts.push(AccountMeta::new(*account_pubkey, false));
1025    accounts.push(AccountMeta::new_readonly(
1026        *owner_pubkey,
1027        signer_pubkeys.is_empty(),
1028    ));
1029    for signer_pubkey in signer_pubkeys.iter() {
1030        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1031    }
1032
1033    Ok(Instruction {
1034        program_id: *token_program_id,
1035        accounts,
1036        data,
1037    })
1038}
1039
1040/// Creates a `Burn` instruction.
1041pub fn burn(
1042    token_program_id: &Pubkey,
1043    account_pubkey: &Pubkey,
1044    mint_pubkey: &Pubkey,
1045    authority_pubkey: &Pubkey,
1046    signer_pubkeys: &[&Pubkey],
1047    amount: u64,
1048) -> Result<Instruction, ProgramError> {
1049    check_program_account(token_program_id)?;
1050    let data = TokenInstruction::Burn { amount }.pack();
1051
1052    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1053    accounts.push(AccountMeta::new(*account_pubkey, false));
1054    accounts.push(AccountMeta::new(*mint_pubkey, false));
1055    accounts.push(AccountMeta::new_readonly(
1056        *authority_pubkey,
1057        signer_pubkeys.is_empty(),
1058    ));
1059    for signer_pubkey in signer_pubkeys.iter() {
1060        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1061    }
1062
1063    Ok(Instruction {
1064        program_id: *token_program_id,
1065        accounts,
1066        data,
1067    })
1068}
1069
1070/// Creates a `CloseAccount` instruction.
1071pub fn close_account(
1072    token_program_id: &Pubkey,
1073    account_pubkey: &Pubkey,
1074    destination_pubkey: &Pubkey,
1075    owner_pubkey: &Pubkey,
1076    signer_pubkeys: &[&Pubkey],
1077) -> Result<Instruction, ProgramError> {
1078    check_program_account(token_program_id)?;
1079    let data = TokenInstruction::CloseAccount.pack();
1080
1081    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1082    accounts.push(AccountMeta::new(*account_pubkey, false));
1083    accounts.push(AccountMeta::new(*destination_pubkey, false));
1084    accounts.push(AccountMeta::new_readonly(
1085        *owner_pubkey,
1086        signer_pubkeys.is_empty(),
1087    ));
1088    for signer_pubkey in signer_pubkeys.iter() {
1089        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1090    }
1091
1092    Ok(Instruction {
1093        program_id: *token_program_id,
1094        accounts,
1095        data,
1096    })
1097}
1098
1099/// Creates a `FreezeAccount` instruction.
1100pub fn freeze_account(
1101    token_program_id: &Pubkey,
1102    account_pubkey: &Pubkey,
1103    mint_pubkey: &Pubkey,
1104    owner_pubkey: &Pubkey,
1105    signer_pubkeys: &[&Pubkey],
1106) -> Result<Instruction, ProgramError> {
1107    check_program_account(token_program_id)?;
1108    let data = TokenInstruction::FreezeAccount.pack();
1109
1110    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1111    accounts.push(AccountMeta::new(*account_pubkey, false));
1112    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1113    accounts.push(AccountMeta::new_readonly(
1114        *owner_pubkey,
1115        signer_pubkeys.is_empty(),
1116    ));
1117    for signer_pubkey in signer_pubkeys.iter() {
1118        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1119    }
1120
1121    Ok(Instruction {
1122        program_id: *token_program_id,
1123        accounts,
1124        data,
1125    })
1126}
1127
1128/// Creates a `ThawAccount` instruction.
1129pub fn thaw_account(
1130    token_program_id: &Pubkey,
1131    account_pubkey: &Pubkey,
1132    mint_pubkey: &Pubkey,
1133    owner_pubkey: &Pubkey,
1134    signer_pubkeys: &[&Pubkey],
1135) -> Result<Instruction, ProgramError> {
1136    check_program_account(token_program_id)?;
1137    let data = TokenInstruction::ThawAccount.pack();
1138
1139    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1140    accounts.push(AccountMeta::new(*account_pubkey, false));
1141    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1142    accounts.push(AccountMeta::new_readonly(
1143        *owner_pubkey,
1144        signer_pubkeys.is_empty(),
1145    ));
1146    for signer_pubkey in signer_pubkeys.iter() {
1147        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1148    }
1149
1150    Ok(Instruction {
1151        program_id: *token_program_id,
1152        accounts,
1153        data,
1154    })
1155}
1156
1157/// Creates a `TransferChecked` instruction.
1158#[allow(clippy::too_many_arguments)]
1159pub fn transfer_checked(
1160    token_program_id: &Pubkey,
1161    source_pubkey: &Pubkey,
1162    mint_pubkey: &Pubkey,
1163    destination_pubkey: &Pubkey,
1164    authority_pubkey: &Pubkey,
1165    signer_pubkeys: &[&Pubkey],
1166    amount: u64,
1167    decimals: u8,
1168) -> Result<Instruction, ProgramError> {
1169    check_program_account(token_program_id)?;
1170    let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1171
1172    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1173    accounts.push(AccountMeta::new(*source_pubkey, false));
1174    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1175    accounts.push(AccountMeta::new(*destination_pubkey, false));
1176    accounts.push(AccountMeta::new_readonly(
1177        *authority_pubkey,
1178        signer_pubkeys.is_empty(),
1179    ));
1180    for signer_pubkey in signer_pubkeys.iter() {
1181        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1182    }
1183
1184    Ok(Instruction {
1185        program_id: *token_program_id,
1186        accounts,
1187        data,
1188    })
1189}
1190
1191/// Creates an `ApproveChecked` instruction.
1192#[allow(clippy::too_many_arguments)]
1193pub fn approve_checked(
1194    token_program_id: &Pubkey,
1195    source_pubkey: &Pubkey,
1196    mint_pubkey: &Pubkey,
1197    delegate_pubkey: &Pubkey,
1198    owner_pubkey: &Pubkey,
1199    signer_pubkeys: &[&Pubkey],
1200    amount: u64,
1201    decimals: u8,
1202) -> Result<Instruction, ProgramError> {
1203    check_program_account(token_program_id)?;
1204    let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1205
1206    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1207    accounts.push(AccountMeta::new(*source_pubkey, false));
1208    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1209    accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1210    accounts.push(AccountMeta::new_readonly(
1211        *owner_pubkey,
1212        signer_pubkeys.is_empty(),
1213    ));
1214    for signer_pubkey in signer_pubkeys.iter() {
1215        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1216    }
1217
1218    Ok(Instruction {
1219        program_id: *token_program_id,
1220        accounts,
1221        data,
1222    })
1223}
1224
1225/// Creates a `MintToChecked` instruction.
1226pub fn mint_to_checked(
1227    token_program_id: &Pubkey,
1228    mint_pubkey: &Pubkey,
1229    account_pubkey: &Pubkey,
1230    owner_pubkey: &Pubkey,
1231    signer_pubkeys: &[&Pubkey],
1232    amount: u64,
1233    decimals: u8,
1234) -> Result<Instruction, ProgramError> {
1235    check_program_account(token_program_id)?;
1236    let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1237
1238    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1239    accounts.push(AccountMeta::new(*mint_pubkey, false));
1240    accounts.push(AccountMeta::new(*account_pubkey, false));
1241    accounts.push(AccountMeta::new_readonly(
1242        *owner_pubkey,
1243        signer_pubkeys.is_empty(),
1244    ));
1245    for signer_pubkey in signer_pubkeys.iter() {
1246        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1247    }
1248
1249    Ok(Instruction {
1250        program_id: *token_program_id,
1251        accounts,
1252        data,
1253    })
1254}
1255
1256/// Creates a `BurnChecked` instruction.
1257pub fn burn_checked(
1258    token_program_id: &Pubkey,
1259    account_pubkey: &Pubkey,
1260    mint_pubkey: &Pubkey,
1261    authority_pubkey: &Pubkey,
1262    signer_pubkeys: &[&Pubkey],
1263    amount: u64,
1264    decimals: u8,
1265) -> Result<Instruction, ProgramError> {
1266    check_program_account(token_program_id)?;
1267    let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1268
1269    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1270    accounts.push(AccountMeta::new(*account_pubkey, false));
1271    accounts.push(AccountMeta::new(*mint_pubkey, false));
1272    accounts.push(AccountMeta::new_readonly(
1273        *authority_pubkey,
1274        signer_pubkeys.is_empty(),
1275    ));
1276    for signer_pubkey in signer_pubkeys.iter() {
1277        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1278    }
1279
1280    Ok(Instruction {
1281        program_id: *token_program_id,
1282        accounts,
1283        data,
1284    })
1285}
1286
1287/// Creates a `SyncNative` instruction
1288pub fn sync_native(
1289    token_program_id: &Pubkey,
1290    account_pubkey: &Pubkey,
1291) -> Result<Instruction, ProgramError> {
1292    check_program_account(token_program_id)?;
1293
1294    Ok(Instruction {
1295        program_id: *token_program_id,
1296        accounts: vec![AccountMeta::new(*account_pubkey, false)],
1297        data: TokenInstruction::SyncNative.pack(),
1298    })
1299}
1300
1301/// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS
1302pub fn is_valid_signer_index(index: usize) -> bool {
1303    (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1304}
1305
1306#[cfg(test)]
1307mod test {
1308    use super::*;
1309
1310    #[test]
1311    fn test_instruction_packing() {
1312        let check = TokenInstruction::InitializeMint {
1313            decimals: 2,
1314            mint_authority: Pubkey::new(&[1u8; 32]),
1315            freeze_authority: COption::None,
1316        };
1317        let packed = check.pack();
1318        let mut expect = Vec::from([0u8, 2]);
1319        expect.extend_from_slice(&[1u8; 32]);
1320        expect.extend_from_slice(&[0]);
1321        assert_eq!(packed, expect);
1322        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1323        assert_eq!(unpacked, check);
1324
1325        let check = TokenInstruction::InitializeMint {
1326            decimals: 2,
1327            mint_authority: Pubkey::new(&[2u8; 32]),
1328            freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
1329        };
1330        let packed = check.pack();
1331        let mut expect = vec![0u8, 2];
1332        expect.extend_from_slice(&[2u8; 32]);
1333        expect.extend_from_slice(&[1]);
1334        expect.extend_from_slice(&[3u8; 32]);
1335        assert_eq!(packed, expect);
1336        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1337        assert_eq!(unpacked, check);
1338
1339        let check = TokenInstruction::InitializeAccount;
1340        let packed = check.pack();
1341        let expect = Vec::from([1u8]);
1342        assert_eq!(packed, expect);
1343        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1344        assert_eq!(unpacked, check);
1345
1346        let check = TokenInstruction::InitializeMultisig { m: 1 };
1347        let packed = check.pack();
1348        let expect = Vec::from([2u8, 1]);
1349        assert_eq!(packed, expect);
1350        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1351        assert_eq!(unpacked, check);
1352
1353        let check = TokenInstruction::Transfer { amount: 1 };
1354        let packed = check.pack();
1355        let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1356        assert_eq!(packed, expect);
1357        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1358        assert_eq!(unpacked, check);
1359
1360        let check = TokenInstruction::Approve { amount: 1 };
1361        let packed = check.pack();
1362        let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1363        assert_eq!(packed, expect);
1364        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1365        assert_eq!(unpacked, check);
1366
1367        let check = TokenInstruction::Revoke;
1368        let packed = check.pack();
1369        let expect = Vec::from([5u8]);
1370        assert_eq!(packed, expect);
1371        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1372        assert_eq!(unpacked, check);
1373
1374        let check = TokenInstruction::SetAuthority {
1375            authority_type: AuthorityType::FreezeAccount,
1376            new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
1377        };
1378        let packed = check.pack();
1379        let mut expect = Vec::from([6u8, 1]);
1380        expect.extend_from_slice(&[1]);
1381        expect.extend_from_slice(&[4u8; 32]);
1382        assert_eq!(packed, expect);
1383        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1384        assert_eq!(unpacked, check);
1385
1386        let check = TokenInstruction::MintTo { amount: 1 };
1387        let packed = check.pack();
1388        let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1389        assert_eq!(packed, expect);
1390        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1391        assert_eq!(unpacked, check);
1392
1393        let check = TokenInstruction::Burn { amount: 1 };
1394        let packed = check.pack();
1395        let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
1396        assert_eq!(packed, expect);
1397        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1398        assert_eq!(unpacked, check);
1399
1400        let check = TokenInstruction::CloseAccount;
1401        let packed = check.pack();
1402        let expect = Vec::from([9u8]);
1403        assert_eq!(packed, expect);
1404        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1405        assert_eq!(unpacked, check);
1406
1407        let check = TokenInstruction::FreezeAccount;
1408        let packed = check.pack();
1409        let expect = Vec::from([10u8]);
1410        assert_eq!(packed, expect);
1411        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1412        assert_eq!(unpacked, check);
1413
1414        let check = TokenInstruction::ThawAccount;
1415        let packed = check.pack();
1416        let expect = Vec::from([11u8]);
1417        assert_eq!(packed, expect);
1418        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1419        assert_eq!(unpacked, check);
1420
1421        let check = TokenInstruction::TransferChecked {
1422            amount: 1,
1423            decimals: 2,
1424        };
1425        let packed = check.pack();
1426        let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1427        assert_eq!(packed, expect);
1428        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1429        assert_eq!(unpacked, check);
1430
1431        let check = TokenInstruction::ApproveChecked {
1432            amount: 1,
1433            decimals: 2,
1434        };
1435        let packed = check.pack();
1436        let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1437        assert_eq!(packed, expect);
1438        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1439        assert_eq!(unpacked, check);
1440
1441        let check = TokenInstruction::MintToChecked {
1442            amount: 1,
1443            decimals: 2,
1444        };
1445        let packed = check.pack();
1446        let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1447        assert_eq!(packed, expect);
1448        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1449        assert_eq!(unpacked, check);
1450
1451        let check = TokenInstruction::BurnChecked {
1452            amount: 1,
1453            decimals: 2,
1454        };
1455        let packed = check.pack();
1456        let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
1457        assert_eq!(packed, expect);
1458        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1459        assert_eq!(unpacked, check);
1460
1461        let check = TokenInstruction::InitializeAccount2 {
1462            owner: Pubkey::new(&[2u8; 32]),
1463        };
1464        let packed = check.pack();
1465        let mut expect = vec![16u8];
1466        expect.extend_from_slice(&[2u8; 32]);
1467        assert_eq!(packed, expect);
1468        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1469        assert_eq!(unpacked, check);
1470
1471        let check = TokenInstruction::SyncNative;
1472        let packed = check.pack();
1473        let expect = vec![17u8];
1474        assert_eq!(packed, expect);
1475        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1476        assert_eq!(unpacked, check);
1477
1478        let check = TokenInstruction::InitializeAccount3 {
1479            owner: Pubkey::new(&[2u8; 32]),
1480        };
1481        let packed = check.pack();
1482        let mut expect = vec![18u8];
1483        expect.extend_from_slice(&[2u8; 32]);
1484        assert_eq!(packed, expect);
1485        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1486        assert_eq!(unpacked, check);
1487
1488        let check = TokenInstruction::InitializeMultisig2 { m: 1 };
1489        let packed = check.pack();
1490        let expect = Vec::from([19u8, 1]);
1491        assert_eq!(packed, expect);
1492        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1493        assert_eq!(unpacked, check);
1494
1495        let check = TokenInstruction::InitializeMint2 {
1496            decimals: 2,
1497            mint_authority: Pubkey::new(&[1u8; 32]),
1498            freeze_authority: COption::None,
1499        };
1500        let packed = check.pack();
1501        let mut expect = Vec::from([20u8, 2]);
1502        expect.extend_from_slice(&[1u8; 32]);
1503        expect.extend_from_slice(&[0]);
1504        assert_eq!(packed, expect);
1505        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1506        assert_eq!(unpacked, check);
1507
1508        let check = TokenInstruction::InitializeMint2 {
1509            decimals: 2,
1510            mint_authority: Pubkey::new(&[2u8; 32]),
1511            freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
1512        };
1513        let packed = check.pack();
1514        let mut expect = vec![20u8, 2];
1515        expect.extend_from_slice(&[2u8; 32]);
1516        expect.extend_from_slice(&[1]);
1517        expect.extend_from_slice(&[3u8; 32]);
1518        assert_eq!(packed, expect);
1519        let unpacked = TokenInstruction::unpack(&expect).unwrap();
1520        assert_eq!(unpacked, check);
1521    }
1522}