apl_token/
instruction.rs

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