spl_token/
instruction.rs

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