spl_token_2022_interface/
instruction.rs

1//! Instruction types
2
3// Needed to avoid deprecation warning when generating serde implementation for
4// TokenInstruction
5#![allow(deprecated)]
6
7#[cfg(feature = "serde")]
8use {
9    crate::serialization::coption_fromstr,
10    serde::{Deserialize, Serialize},
11    serde_with::{As, DisplayFromStr},
12};
13use {
14    crate::{
15        check_program_account, check_spl_token_program_account, error::TokenError,
16        extension::ExtensionType,
17    },
18    bytemuck::Pod,
19    solana_instruction::{AccountMeta, Instruction},
20    solana_program_error::ProgramError,
21    solana_program_option::COption,
22    solana_pubkey::{Pubkey, PUBKEY_BYTES},
23    solana_sdk_ids::{system_program, sysvar},
24    spl_pod::bytemuck::{pod_from_bytes, pod_get_packed_len},
25    std::{
26        convert::{TryFrom, TryInto},
27        mem::size_of,
28    },
29};
30
31/// Minimum number of multisignature signers (min N)
32pub const MIN_SIGNERS: usize = 1;
33/// Maximum number of multisignature signers (max N)
34pub const MAX_SIGNERS: usize = 11;
35/// Serialized length of a `u16`, for unpacking
36const U16_BYTES: usize = 2;
37/// Serialized length of a `u64`, for unpacking
38const U64_BYTES: usize = 8;
39
40/// Instructions supported by the token program.
41#[repr(C)]
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43#[cfg_attr(
44    feature = "serde",
45    serde(rename_all_fields = "camelCase", rename_all = "camelCase")
46)]
47#[derive(Clone, Debug, PartialEq)]
48pub enum TokenInstruction<'a> {
49    // 0
50    /// Initializes a new mint and optionally deposits all the newly minted
51    /// tokens in an account.
52    ///
53    /// The `InitializeMint` 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    /// All extensions must be initialized before calling this instruction.
60    ///
61    /// Accounts expected by this instruction:
62    ///
63    ///   0. `[writable]` The mint to initialize.
64    ///   1. `[]` Rent sysvar
65    InitializeMint {
66        /// Number of base 10 digits to the right of the decimal place.
67        decimals: u8,
68        /// The authority/multisignature to mint tokens.
69        #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
70        mint_authority: Pubkey,
71        /// The freeze authority/multisignature of the mint.
72        #[cfg_attr(feature = "serde", serde(with = "coption_fromstr"))]
73        freeze_authority: COption<Pubkey>,
74    },
75    /// Initializes a new account to hold tokens.  If this account is associated
76    /// with the native mint then the token balance of the initialized account
77    /// will be equal to the amount of SOL in the account. If this account is
78    /// associated with another mint, that mint must be initialized before this
79    /// command can succeed.
80    ///
81    /// The `InitializeAccount` instruction requires no signers and MUST be
82    /// included within the same Transaction as the system program's
83    /// `CreateAccount` instruction that creates the account being initialized.
84    /// Otherwise another party can acquire ownership of the uninitialized
85    /// account.
86    ///
87    /// Accounts expected by this instruction:
88    ///
89    ///   0. `[writable]`  The account to initialize.
90    ///   1. `[]` The mint this account will be associated with.
91    ///   2. `[]` The new account's owner/multisignature.
92    ///   3. `[]` Rent sysvar
93    InitializeAccount,
94    /// Initializes a multisignature account with N provided signers.
95    ///
96    /// Multisignature accounts can used in place of any single owner/delegate
97    /// accounts in any token instruction that require an owner/delegate to be
98    /// present.  The variant field represents the number of signers (M)
99    /// required to validate this multisignature account.
100    ///
101    /// The `InitializeMultisig` instruction requires no signers and MUST be
102    /// included within the same Transaction as the system program's
103    /// `CreateAccount` instruction that creates the account being initialized.
104    /// Otherwise another party can acquire ownership of the uninitialized
105    /// account.
106    ///
107    /// Accounts expected by this instruction:
108    ///
109    ///   0. `[writable]` The multisignature account to initialize.
110    ///   1. `[]` Rent sysvar
111    ///   2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
112    ///      11`.
113    InitializeMultisig {
114        /// The number of signers (M) required to validate this multisignature
115        /// account.
116        m: u8,
117    },
118    /// NOTE This instruction is deprecated in favor of `TransferChecked` or
119    /// `TransferCheckedWithFee`
120    ///
121    /// Transfers tokens from one account to another either directly or via a
122    /// delegate.  If this account is associated with the native mint then equal
123    /// amounts of SOL and Tokens will be transferred to the destination
124    /// account.
125    ///
126    /// If either account contains an `TransferFeeAmount` extension, this will
127    /// fail. Mints with the `TransferFeeConfig` extension are required in
128    /// order to assess the fee.
129    ///
130    /// Accounts expected by this instruction:
131    ///
132    ///   * Single owner/delegate
133    ///   0. `[writable]` The source account.
134    ///   1. `[writable]` The destination account.
135    ///   2. `[signer]` The source account's owner/delegate.
136    ///
137    ///   * Multisignature owner/delegate
138    ///   0. `[writable]` The source account.
139    ///   1. `[writable]` The destination account.
140    ///   2. `[]` The source account's multisignature owner/delegate.
141    ///   3. ..`3+M` `[signer]` M signer accounts.
142    #[deprecated(
143        since = "4.0.0",
144        note = "please use `TransferChecked` or `TransferCheckedWithFee` instead"
145    )]
146    Transfer {
147        /// The amount of tokens to transfer.
148        amount: u64,
149    },
150    /// Approves a delegate.  A delegate is given the authority over tokens on
151    /// behalf of the source account's owner.
152    ///
153    /// Accounts expected by this instruction:
154    ///
155    ///   * Single owner
156    ///   0. `[writable]` The source account.
157    ///   1. `[]` The delegate.
158    ///   2. `[signer]` The source account owner.
159    ///
160    ///   * Multisignature owner
161    ///   0. `[writable]` The source account.
162    ///   1. `[]` The delegate.
163    ///   2. `[]` The source account's multisignature owner.
164    ///   3. ..`3+M` `[signer]` M signer accounts
165    Approve {
166        /// The amount of tokens the delegate is approved for.
167        amount: u64,
168    },
169    // 5
170    /// Revokes the delegate's authority.
171    ///
172    /// Accounts expected by this instruction:
173    ///
174    ///   * Single owner
175    ///   0. `[writable]` The source account.
176    ///   1. `[signer]` The source account owner or current delegate.
177    ///
178    ///   * Multisignature owner
179    ///   0. `[writable]` The source account.
180    ///   1. `[]` The source account's multisignature owner or current delegate.
181    ///   2. ..`2+M` `[signer]` M signer accounts
182    Revoke,
183    /// Sets a new authority of a mint or account.
184    ///
185    /// Accounts expected by this instruction:
186    ///
187    ///   * Single authority
188    ///   0. `[writable]` The mint or account to change the authority of.
189    ///   1. `[signer]` The current authority of the mint or account.
190    ///
191    ///   * Multisignature authority
192    ///   0. `[writable]` The mint or account to change the authority of.
193    ///   1. `[]` The mint's or account's current multisignature authority.
194    ///   2. ..`2+M` `[signer]` M signer accounts
195    SetAuthority {
196        /// The type of authority to update.
197        authority_type: AuthorityType,
198        /// The new authority
199        #[cfg_attr(feature = "serde", serde(with = "coption_fromstr"))]
200        new_authority: COption<Pubkey>,
201    },
202    /// Mints new tokens to an account.  The native mint does not support
203    /// minting.
204    ///
205    /// Accounts expected by this instruction:
206    ///
207    ///   * Single authority
208    ///   0. `[writable]` The mint.
209    ///   1. `[writable]` The account to mint tokens to.
210    ///   2. `[signer]` The mint's minting authority.
211    ///
212    ///   * Multisignature authority
213    ///   0. `[writable]` The mint.
214    ///   1. `[writable]` The account to mint tokens to.
215    ///   2. `[]` The mint's multisignature mint-tokens authority.
216    ///   3. ..`3+M` `[signer]` M signer accounts.
217    MintTo {
218        /// The amount of new tokens to mint.
219        amount: u64,
220    },
221    /// Burns tokens by removing them from an account.  `Burn` does not support
222    /// accounts associated with the native mint, use `CloseAccount` instead.
223    ///
224    /// Accounts expected by this instruction:
225    ///
226    ///   * Single owner/delegate
227    ///   0. `[writable]` The account to burn from.
228    ///   1. `[writable]` The token mint.
229    ///   2. `[signer]` The account's owner/delegate.
230    ///
231    ///   * Multisignature owner/delegate
232    ///   0. `[writable]` The account to burn from.
233    ///   1. `[writable]` The token mint.
234    ///   2. `[]` The account's multisignature owner/delegate.
235    ///   3. ..`3+M` `[signer]` M signer accounts.
236    Burn {
237        /// The amount of tokens to burn.
238        amount: u64,
239    },
240    /// Close an account by transferring all its SOL to the destination account.
241    /// Non-native accounts may only be closed if its token amount is zero.
242    ///
243    /// Accounts with the `TransferFeeAmount` extension may only be closed if
244    /// the withheld amount is zero.
245    ///
246    /// Accounts with the `ConfidentialTransfer` extension may only be closed if
247    /// the pending and available balance ciphertexts are empty. Use
248    /// `ConfidentialTransferInstruction::ApplyPendingBalance` and
249    /// `ConfidentialTransferInstruction::EmptyAccount` to empty these
250    /// ciphertexts.
251    ///
252    /// Accounts with the `ConfidentialTransferFee` extension may only be closed
253    /// if the withheld amount ciphertext is empty. Use
254    /// `ConfidentialTransferFeeInstruction::HarvestWithheldTokensToMint` to
255    /// empty this ciphertext.
256    ///
257    /// Mints may be closed if they have the `MintCloseAuthority` extension and
258    /// their token supply is zero
259    ///
260    /// Accounts
261    ///
262    /// Accounts expected by this instruction:
263    ///
264    ///   * Single owner
265    ///   0. `[writable]` The account to close.
266    ///   1. `[writable]` The destination account.
267    ///   2. `[signer]` The account's owner.
268    ///
269    ///   * Multisignature owner
270    ///   0. `[writable]` The account to close.
271    ///   1. `[writable]` The destination account.
272    ///   2. `[]` The account's multisignature owner.
273    ///   3. ..`3+M` `[signer]` M signer accounts.
274    CloseAccount,
275    // 10
276    /// Freeze an Initialized account using the Mint's `freeze_authority` (if
277    /// set).
278    ///
279    /// Accounts expected by this instruction:
280    ///
281    ///   * Single owner
282    ///   0. `[writable]` The account to freeze.
283    ///   1. `[]` The token mint.
284    ///   2. `[signer]` The mint freeze authority.
285    ///
286    ///   * Multisignature owner
287    ///   0. `[writable]` The account to freeze.
288    ///   1. `[]` The token mint.
289    ///   2. `[]` The mint's multisignature freeze authority.
290    ///   3. ..`3+M` `[signer]` M signer accounts.
291    FreezeAccount,
292    /// Thaw a Frozen account using the Mint's `freeze_authority` (if set).
293    ///
294    /// Accounts expected by this instruction:
295    ///
296    ///   * Single owner
297    ///   0. `[writable]` The account to freeze.
298    ///   1. `[]` The token mint.
299    ///   2. `[signer]` The mint freeze authority.
300    ///
301    ///   * Multisignature owner
302    ///   0. `[writable]` The account to freeze.
303    ///   1. `[]` The token mint.
304    ///   2. `[]` The mint's multisignature freeze authority.
305    ///   3. ..`3+M` `[signer]` M signer accounts.
306    ThawAccount,
307
308    /// Transfers tokens from one account to another either directly or via a
309    /// delegate.  If this account is associated with the native mint then equal
310    /// amounts of SOL and Tokens will be transferred to the destination
311    /// account.
312    ///
313    /// This instruction differs from `Transfer` in that the token mint and
314    /// decimals value is checked by the caller.  This may be useful when
315    /// creating transactions offline or within a hardware wallet.
316    ///
317    /// If either account contains an `TransferFeeAmount` extension, the fee is
318    /// withheld in the destination account.
319    ///
320    /// Accounts expected by this instruction:
321    ///
322    ///   * Single owner/delegate
323    ///   0. `[writable]` The source account.
324    ///   1. `[]` The token mint.
325    ///   2. `[writable]` The destination account.
326    ///   3. `[signer]` The source account's owner/delegate.
327    ///
328    ///   * Multisignature owner/delegate
329    ///   0. `[writable]` The source account.
330    ///   1. `[]` The token mint.
331    ///   2. `[writable]` The destination account.
332    ///   3. `[]` The source account's multisignature owner/delegate.
333    ///   4. ..`4+M` `[signer]` M signer accounts.
334    TransferChecked {
335        /// The amount of tokens to transfer.
336        amount: u64,
337        /// Expected number of base 10 digits to the right of the decimal place.
338        decimals: u8,
339    },
340    /// Approves a delegate.  A delegate is given the authority over tokens on
341    /// behalf of the source account's owner.
342    ///
343    /// This instruction differs from `Approve` in that the token mint and
344    /// decimals value is checked by the caller.  This may be useful when
345    /// creating transactions offline or within a hardware wallet.
346    ///
347    /// Accounts expected by this instruction:
348    ///
349    ///   * Single owner
350    ///   0. `[writable]` The source account.
351    ///   1. `[]` The token mint.
352    ///   2. `[]` The delegate.
353    ///   3. `[signer]` The source account owner.
354    ///
355    ///   * Multisignature owner
356    ///   0. `[writable]` The source account.
357    ///   1. `[]` The token mint.
358    ///   2. `[]` The delegate.
359    ///   3. `[]` The source account's multisignature owner.
360    ///   4. ..`4+M` `[signer]` M signer accounts
361    ApproveChecked {
362        /// The amount of tokens the delegate is approved for.
363        amount: u64,
364        /// Expected number of base 10 digits to the right of the decimal place.
365        decimals: u8,
366    },
367    /// Mints new tokens to an account.  The native mint does not support
368    /// minting.
369    ///
370    /// This instruction differs from `MintTo` in that the decimals value is
371    /// checked by the caller.  This may be useful when creating transactions
372    /// offline or within a hardware wallet.
373    ///
374    /// Accounts expected by this instruction:
375    ///
376    ///   * Single authority
377    ///   0. `[writable]` The mint.
378    ///   1. `[writable]` The account to mint tokens to.
379    ///   2. `[signer]` The mint's minting authority.
380    ///
381    ///   * Multisignature authority
382    ///   0. `[writable]` The mint.
383    ///   1. `[writable]` The account to mint tokens to.
384    ///   2. `[]` The mint's multisignature mint-tokens authority.
385    ///   3. ..`3+M` `[signer]` M signer accounts.
386    MintToChecked {
387        /// The amount of new tokens to mint.
388        amount: u64,
389        /// Expected number of base 10 digits to the right of the decimal place.
390        decimals: u8,
391    },
392    // 15
393    /// Burns tokens by removing them from an account.  `BurnChecked` does not
394    /// support accounts associated with the native mint, use `CloseAccount`
395    /// instead.
396    ///
397    /// This instruction differs from `Burn` in that the decimals value is
398    /// checked by the caller. This may be useful when creating transactions
399    /// offline or within a hardware wallet.
400    ///
401    /// Accounts expected by this instruction:
402    ///
403    ///   * Single owner/delegate
404    ///   0. `[writable]` The account to burn from.
405    ///   1. `[writable]` The token mint.
406    ///   2. `[signer]` The account's owner/delegate.
407    ///
408    ///   * Multisignature owner/delegate
409    ///   0. `[writable]` The account to burn from.
410    ///   1. `[writable]` The token mint.
411    ///   2. `[]` The account's multisignature owner/delegate.
412    ///   3. ..`3+M` `[signer]` M signer accounts.
413    BurnChecked {
414        /// The amount of tokens to burn.
415        amount: u64,
416        /// Expected number of base 10 digits to the right of the decimal place.
417        decimals: u8,
418    },
419    /// Like `InitializeAccount`, but the owner pubkey is passed via instruction
420    /// data rather than the accounts list. This variant may be preferable
421    /// when using Cross Program Invocation from an instruction that does
422    /// not need the owner's `AccountInfo` otherwise.
423    ///
424    /// Accounts expected by this instruction:
425    ///
426    ///   0. `[writable]`  The account to initialize.
427    ///   1. `[]` The mint this account will be associated with.
428    ///   2. `[]` Rent sysvar
429    InitializeAccount2 {
430        /// The new account's owner/multisignature.
431        #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
432        owner: Pubkey,
433    },
434    /// Given a wrapped / native token account (a token account containing SOL)
435    /// updates its amount field based on the account's underlying `lamports`.
436    /// This is useful if a non-wrapped SOL account uses
437    /// `system_instruction::transfer` to move lamports to a wrapped token
438    /// account, and needs to have its token `amount` field updated.
439    ///
440    /// Accounts expected by this instruction:
441    ///
442    ///   0. `[writable]`  The native token account to sync with its underlying
443    ///      lamports.
444    SyncNative,
445    /// Like `InitializeAccount2`, but does not require the Rent sysvar to be
446    /// provided
447    ///
448    /// Accounts expected by this instruction:
449    ///
450    ///   0. `[writable]`  The account to initialize.
451    ///   1. `[]` The mint this account will be associated with.
452    InitializeAccount3 {
453        /// The new account's owner/multisignature.
454        #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
455        owner: Pubkey,
456    },
457    /// Like `InitializeMultisig`, but does not require the Rent sysvar to be
458    /// provided
459    ///
460    /// Accounts expected by this instruction:
461    ///
462    ///   0. `[writable]` The multisignature account to initialize.
463    ///   1. ..`1+N`. `[]` The signer accounts, must equal to N where `1 <= N <=
464    ///      11`.
465    InitializeMultisig2 {
466        /// The number of signers (M) required to validate this multisignature
467        /// account.
468        m: u8,
469    },
470    // 20
471    /// Like `InitializeMint`, but does not require the Rent sysvar to be
472    /// provided
473    ///
474    /// Accounts expected by this instruction:
475    ///
476    ///   0. `[writable]` The mint to initialize.
477    InitializeMint2 {
478        /// Number of base 10 digits to the right of the decimal place.
479        decimals: u8,
480        /// The authority/multisignature to mint tokens.
481        #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
482        mint_authority: Pubkey,
483        /// The freeze authority/multisignature of the mint.
484        #[cfg_attr(feature = "serde", serde(with = "coption_fromstr"))]
485        freeze_authority: COption<Pubkey>,
486    },
487    /// Gets the required size of an account for the given mint as a
488    /// little-endian `u64`.
489    ///
490    /// Return data can be fetched using `sol_get_return_data` and deserializing
491    /// the return data as a little-endian `u64`.
492    ///
493    /// Accounts expected by this instruction:
494    ///
495    ///   0. `[]` The mint to calculate for
496    GetAccountDataSize {
497        /// Additional extension types to include in the returned account size
498        extension_types: Vec<ExtensionType>,
499    },
500    /// Initialize the Immutable Owner extension for the given token account
501    ///
502    /// Fails if the account has already been initialized, so must be called
503    /// before `InitializeAccount`.
504    ///
505    /// Accounts expected by this instruction:
506    ///
507    ///   0. `[writable]`  The account to initialize.
508    ///
509    /// Data expected by this instruction:
510    ///   None
511    InitializeImmutableOwner,
512    /// Convert an Amount of tokens to a `UiAmount` string, using the given
513    /// mint.
514    ///
515    /// Fails on an invalid mint.
516    ///
517    /// Return data can be fetched using `sol_get_return_data` and deserialized
518    /// with `String::from_utf8`.
519    ///
520    /// WARNING: For mints using the interest-bearing or scaled-ui-amount
521    /// extensions, this instruction uses standard floating-point arithmetic to
522    /// convert values, which is not guaranteed to give consistent behavior.
523    ///
524    /// In particular, conversions will not always work in reverse. For example,
525    /// if you pass amount `A` to `AmountToUiAmount` and receive `B`, and pass
526    /// the result `B` to `UiAmountToAmount`, you will not always get back `A`.
527    ///
528    /// Accounts expected by this instruction:
529    ///
530    ///   0. `[]` The mint to calculate for
531    AmountToUiAmount {
532        /// The amount of tokens to convert.
533        amount: u64,
534    },
535    /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount,
536    /// using the given mint.
537    ///
538    /// Return data can be fetched using `sol_get_return_data` and deserializing
539    /// the return data as a little-endian `u64`.
540    ///
541    /// WARNING: For mints using the interest-bearing or scaled-ui-amount
542    /// extensions, this instruction uses standard floating-point arithmetic to
543    /// convert values, which is not guaranteed to give consistent behavior.
544    ///
545    /// In particular, conversions will not always work in reverse. For example,
546    /// if you pass amount `A` to `UiAmountToAmount` and receive `B`, and pass
547    /// the result `B` to `AmountToUiAmount`, you will not always get back `A`.
548    ///
549    /// Accounts expected by this instruction:
550    ///
551    ///   0. `[]` The mint to calculate for
552    UiAmountToAmount {
553        /// The `ui_amount` of tokens to convert.
554        ui_amount: &'a str,
555    },
556    // 25
557    /// Initialize the close account authority on a new mint.
558    ///
559    /// Fails if the mint has already been initialized, so must be called before
560    /// `InitializeMint`.
561    ///
562    /// The mint must have exactly enough space allocated for the base mint (82
563    /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
564    /// then space required for this extension, plus any others.
565    ///
566    /// Accounts expected by this instruction:
567    ///
568    ///   0. `[writable]` The mint to initialize.
569    InitializeMintCloseAuthority {
570        /// Authority that must sign the `CloseAccount` instruction on a mint
571        #[cfg_attr(feature = "serde", serde(with = "coption_fromstr"))]
572        close_authority: COption<Pubkey>,
573    },
574    /// The common instruction prefix for Transfer Fee extension instructions.
575    ///
576    /// See `extension::transfer_fee::instruction::TransferFeeInstruction` for
577    /// further details about the extended instructions that share this
578    /// instruction prefix
579    TransferFeeExtension,
580    /// The common instruction prefix for Confidential Transfer extension
581    /// instructions.
582    ///
583    /// See `extension::confidential_transfer::instruction::ConfidentialTransferInstruction` for
584    /// further details about the extended instructions that share this
585    /// instruction prefix
586    ConfidentialTransferExtension,
587    /// The common instruction prefix for Default Account State extension
588    /// instructions.
589    ///
590    /// See `extension::default_account_state::instruction::DefaultAccountStateInstruction` for
591    /// further details about the extended instructions that share this
592    /// instruction prefix
593    DefaultAccountStateExtension,
594    /// Check to see if a token account is large enough for a list of
595    /// `ExtensionTypes`, and if not, use reallocation to increase the data
596    /// size.
597    ///
598    /// Accounts expected by this instruction:
599    ///
600    ///   * Single owner
601    ///   0. `[writable]` The account to reallocate.
602    ///   1. `[signer, writable]` The payer account to fund reallocation
603    ///   2. `[]` System program for reallocation funding
604    ///   3. `[signer]` The account's owner.
605    ///
606    ///   * Multisignature owner
607    ///   0. `[writable]` The account to reallocate.
608    ///   1. `[signer, writable]` The payer account to fund reallocation
609    ///   2. `[]` System program for reallocation funding
610    ///   3. `[]` The account's multisignature owner/delegate.
611    ///   4. ..`4+M` `[signer]` M signer accounts.
612    Reallocate {
613        /// New extension types to include in the reallocated account
614        extension_types: Vec<ExtensionType>,
615    },
616    // 30
617    /// The common instruction prefix for Memo Transfer account extension
618    /// instructions.
619    ///
620    /// See `extension::memo_transfer::instruction::RequiredMemoTransfersInstruction` for
621    /// further details about the extended instructions that share this
622    /// instruction prefix
623    MemoTransferExtension,
624    /// Creates the native mint.
625    ///
626    /// This instruction only needs to be invoked once after deployment and is
627    /// permissionless, Wrapped SOL (`native_mint::id()`) will not be
628    /// available until this instruction is successfully executed.
629    ///
630    /// Accounts expected by this instruction:
631    ///
632    ///   0. `[writeable,signer]` Funding account (must be a system account)
633    ///   1. `[writable]` The native mint address
634    ///   2. `[]` System program for mint account funding
635    CreateNativeMint,
636    /// Initialize the non transferable extension for the given mint account
637    ///
638    /// Fails if the account has already been initialized, so must be called
639    /// before `InitializeMint`.
640    ///
641    /// Accounts expected by this instruction:
642    ///
643    ///   0. `[writable]`  The mint account to initialize.
644    ///
645    /// Data expected by this instruction:
646    ///   None
647    InitializeNonTransferableMint,
648    /// The common instruction prefix for Interest Bearing extension
649    /// instructions.
650    ///
651    /// See `extension::interest_bearing_mint::instruction::InterestBearingMintInstruction` for
652    /// further details about the extended instructions that share this
653    /// instruction prefix
654    InterestBearingMintExtension,
655    /// The common instruction prefix for CPI Guard account extension
656    /// instructions.
657    ///
658    /// See `extension::cpi_guard::instruction::CpiGuardInstruction` for
659    /// further details about the extended instructions that share this
660    /// instruction prefix
661    CpiGuardExtension,
662    // 35
663    /// Initialize the permanent delegate on a new mint.
664    ///
665    /// Fails if the mint has already been initialized, so must be called before
666    /// `InitializeMint`.
667    ///
668    /// The mint must have exactly enough space allocated for the base mint (82
669    /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
670    /// then space required for this extension, plus any others.
671    ///
672    /// Accounts expected by this instruction:
673    ///
674    ///   0. `[writable]` The mint to initialize.
675    ///
676    /// Data expected by this instruction:
677    ///   Pubkey for the permanent delegate
678    InitializePermanentDelegate {
679        /// Authority that may sign for `Transfer`s and `Burn`s on any account
680        #[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
681        delegate: Pubkey,
682    },
683    /// The common instruction prefix for transfer hook extension instructions.
684    ///
685    /// See `extension::transfer_hook::instruction::TransferHookInstruction`
686    /// for further details about the extended instructions that share this
687    /// instruction prefix
688    TransferHookExtension,
689    /// The common instruction prefix for the confidential transfer fee
690    /// extension instructions.
691    ///
692    /// See `extension::confidential_transfer_fee::instruction::ConfidentialTransferFeeInstruction`
693    /// for further details about the extended instructions that share this
694    /// instruction prefix
695    ConfidentialTransferFeeExtension,
696    /// This instruction is to be used to rescue SOL sent to any `TokenProgram`
697    /// owned account by sending them to any other account, leaving behind only
698    /// lamports for rent exemption.
699    ///
700    /// 0. `[writable]` Source Account owned by the token program
701    /// 1. `[writable]` Destination account
702    /// 2. `[signer]` Authority
703    /// 3. ..`3+M` `[signer]` M signer accounts.
704    WithdrawExcessLamports,
705    /// The common instruction prefix for metadata pointer extension
706    /// instructions.
707    ///
708    /// See `extension::metadata_pointer::instruction::MetadataPointerInstruction`
709    /// for further details about the extended instructions that share this
710    /// instruction prefix
711    MetadataPointerExtension,
712    // 40
713    /// The common instruction prefix for group pointer extension instructions.
714    ///
715    /// See `extension::group_pointer::instruction::GroupPointerInstruction`
716    /// for further details about the extended instructions that share this
717    /// instruction prefix
718    GroupPointerExtension,
719    /// The common instruction prefix for group member pointer extension
720    /// instructions.
721    ///
722    /// See `extension::group_member_pointer::instruction::GroupMemberPointerInstruction`
723    /// for further details about the extended instructions that share this
724    /// instruction prefix
725    GroupMemberPointerExtension,
726    /// Instruction prefix for instructions to the confidential-mint-burn
727    /// extension
728    ConfidentialMintBurnExtension,
729    /// Instruction prefix for instructions to the scaled ui amount
730    /// extension
731    ScaledUiAmountExtension,
732    /// Instruction prefix for instructions to the pausable extension
733    PausableExtension,
734}
735impl<'a> TokenInstruction<'a> {
736    /// Unpacks a byte buffer into a
737    /// [`TokenInstruction`](enum.TokenInstruction.html).
738    pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
739        use TokenError::InvalidInstruction;
740
741        let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
742        Ok(match tag {
743            0 => {
744                let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
745                let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
746                let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
747                Self::InitializeMint {
748                    mint_authority,
749                    freeze_authority,
750                    decimals,
751                }
752            }
753            1 => Self::InitializeAccount,
754            2 => {
755                let &m = rest.first().ok_or(InvalidInstruction)?;
756                Self::InitializeMultisig { m }
757            }
758            3 | 4 | 7 | 8 => {
759                let amount = rest
760                    .get(..U64_BYTES)
761                    .and_then(|slice| slice.try_into().ok())
762                    .map(u64::from_le_bytes)
763                    .ok_or(InvalidInstruction)?;
764                match tag {
765                    #[allow(deprecated)]
766                    3 => Self::Transfer { amount },
767                    4 => Self::Approve { amount },
768                    7 => Self::MintTo { amount },
769                    8 => Self::Burn { amount },
770                    _ => unreachable!(),
771                }
772            }
773            5 => Self::Revoke,
774            6 => {
775                let (authority_type, rest) = rest
776                    .split_first()
777                    .ok_or_else(|| ProgramError::from(InvalidInstruction))
778                    .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
779                let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
780
781                Self::SetAuthority {
782                    authority_type,
783                    new_authority,
784                }
785            }
786            9 => Self::CloseAccount,
787            10 => Self::FreezeAccount,
788            11 => Self::ThawAccount,
789            12 => {
790                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
791                Self::TransferChecked { amount, decimals }
792            }
793            13 => {
794                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
795                Self::ApproveChecked { amount, decimals }
796            }
797            14 => {
798                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
799                Self::MintToChecked { amount, decimals }
800            }
801            15 => {
802                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
803                Self::BurnChecked { amount, decimals }
804            }
805            16 => {
806                let (owner, _rest) = Self::unpack_pubkey(rest)?;
807                Self::InitializeAccount2 { owner }
808            }
809            17 => Self::SyncNative,
810            18 => {
811                let (owner, _rest) = Self::unpack_pubkey(rest)?;
812                Self::InitializeAccount3 { owner }
813            }
814            19 => {
815                let &m = rest.first().ok_or(InvalidInstruction)?;
816                Self::InitializeMultisig2 { m }
817            }
818            20 => {
819                let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
820                let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
821                let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
822                Self::InitializeMint2 {
823                    mint_authority,
824                    freeze_authority,
825                    decimals,
826                }
827            }
828            21 => {
829                let mut extension_types = vec![];
830                for chunk in rest.chunks(size_of::<ExtensionType>()) {
831                    extension_types.push(chunk.try_into()?);
832                }
833                Self::GetAccountDataSize { extension_types }
834            }
835            22 => Self::InitializeImmutableOwner,
836            23 => {
837                let (amount, _rest) = Self::unpack_u64(rest)?;
838                Self::AmountToUiAmount { amount }
839            }
840            24 => {
841                let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?;
842                Self::UiAmountToAmount { ui_amount }
843            }
844            25 => {
845                let (close_authority, _rest) = Self::unpack_pubkey_option(rest)?;
846                Self::InitializeMintCloseAuthority { close_authority }
847            }
848            26 => Self::TransferFeeExtension,
849            27 => Self::ConfidentialTransferExtension,
850            28 => Self::DefaultAccountStateExtension,
851            29 => {
852                let mut extension_types = vec![];
853                for chunk in rest.chunks(size_of::<ExtensionType>()) {
854                    extension_types.push(chunk.try_into()?);
855                }
856                Self::Reallocate { extension_types }
857            }
858            30 => Self::MemoTransferExtension,
859            31 => Self::CreateNativeMint,
860            32 => Self::InitializeNonTransferableMint,
861            33 => Self::InterestBearingMintExtension,
862            34 => Self::CpiGuardExtension,
863            35 => {
864                let (delegate, _rest) = Self::unpack_pubkey(rest)?;
865                Self::InitializePermanentDelegate { delegate }
866            }
867            36 => Self::TransferHookExtension,
868            37 => Self::ConfidentialTransferFeeExtension,
869            38 => Self::WithdrawExcessLamports,
870            39 => Self::MetadataPointerExtension,
871            40 => Self::GroupPointerExtension,
872            41 => Self::GroupMemberPointerExtension,
873            42 => Self::ConfidentialMintBurnExtension,
874            43 => Self::ScaledUiAmountExtension,
875            44 => Self::PausableExtension,
876            _ => return Err(TokenError::InvalidInstruction.into()),
877        })
878    }
879
880    /// Packs a [`TokenInstruction`](enum.TokenInstruction.html) into a byte
881    /// buffer.
882    pub fn pack(&self) -> Vec<u8> {
883        let mut buf = Vec::with_capacity(size_of::<Self>());
884        match self {
885            &Self::InitializeMint {
886                ref mint_authority,
887                ref freeze_authority,
888                decimals,
889            } => {
890                buf.push(0);
891                buf.push(decimals);
892                buf.extend_from_slice(mint_authority.as_ref());
893                Self::pack_pubkey_option(freeze_authority, &mut buf);
894            }
895            Self::InitializeAccount => buf.push(1),
896            &Self::InitializeMultisig { m } => {
897                buf.push(2);
898                buf.push(m);
899            }
900            #[allow(deprecated)]
901            &Self::Transfer { amount } => {
902                buf.push(3);
903                buf.extend_from_slice(&amount.to_le_bytes());
904            }
905            &Self::Approve { amount } => {
906                buf.push(4);
907                buf.extend_from_slice(&amount.to_le_bytes());
908            }
909            &Self::MintTo { amount } => {
910                buf.push(7);
911                buf.extend_from_slice(&amount.to_le_bytes());
912            }
913            &Self::Burn { amount } => {
914                buf.push(8);
915                buf.extend_from_slice(&amount.to_le_bytes());
916            }
917            Self::Revoke => buf.push(5),
918            Self::SetAuthority {
919                authority_type,
920                ref new_authority,
921            } => {
922                buf.push(6);
923                buf.push(authority_type.into());
924                Self::pack_pubkey_option(new_authority, &mut buf);
925            }
926            Self::CloseAccount => buf.push(9),
927            Self::FreezeAccount => buf.push(10),
928            Self::ThawAccount => buf.push(11),
929            &Self::TransferChecked { amount, decimals } => {
930                buf.push(12);
931                buf.extend_from_slice(&amount.to_le_bytes());
932                buf.push(decimals);
933            }
934            &Self::ApproveChecked { amount, decimals } => {
935                buf.push(13);
936                buf.extend_from_slice(&amount.to_le_bytes());
937                buf.push(decimals);
938            }
939            &Self::MintToChecked { amount, decimals } => {
940                buf.push(14);
941                buf.extend_from_slice(&amount.to_le_bytes());
942                buf.push(decimals);
943            }
944            &Self::BurnChecked { amount, decimals } => {
945                buf.push(15);
946                buf.extend_from_slice(&amount.to_le_bytes());
947                buf.push(decimals);
948            }
949            &Self::InitializeAccount2 { owner } => {
950                buf.push(16);
951                buf.extend_from_slice(owner.as_ref());
952            }
953            &Self::SyncNative => {
954                buf.push(17);
955            }
956            &Self::InitializeAccount3 { owner } => {
957                buf.push(18);
958                buf.extend_from_slice(owner.as_ref());
959            }
960            &Self::InitializeMultisig2 { m } => {
961                buf.push(19);
962                buf.push(m);
963            }
964            &Self::InitializeMint2 {
965                ref mint_authority,
966                ref freeze_authority,
967                decimals,
968            } => {
969                buf.push(20);
970                buf.push(decimals);
971                buf.extend_from_slice(mint_authority.as_ref());
972                Self::pack_pubkey_option(freeze_authority, &mut buf);
973            }
974            Self::GetAccountDataSize { extension_types } => {
975                buf.push(21);
976                for extension_type in extension_types {
977                    buf.extend_from_slice(&<[u8; 2]>::from(*extension_type));
978                }
979            }
980            &Self::InitializeImmutableOwner => {
981                buf.push(22);
982            }
983            &Self::AmountToUiAmount { amount } => {
984                buf.push(23);
985                buf.extend_from_slice(&amount.to_le_bytes());
986            }
987            Self::UiAmountToAmount { ui_amount } => {
988                buf.push(24);
989                buf.extend_from_slice(ui_amount.as_bytes());
990            }
991            Self::InitializeMintCloseAuthority { close_authority } => {
992                buf.push(25);
993                Self::pack_pubkey_option(close_authority, &mut buf);
994            }
995            Self::TransferFeeExtension => {
996                buf.push(26);
997            }
998            &Self::ConfidentialTransferExtension => {
999                buf.push(27);
1000            }
1001            &Self::DefaultAccountStateExtension => {
1002                buf.push(28);
1003            }
1004            Self::Reallocate { extension_types } => {
1005                buf.push(29);
1006                for extension_type in extension_types {
1007                    buf.extend_from_slice(&<[u8; 2]>::from(*extension_type));
1008                }
1009            }
1010            &Self::MemoTransferExtension => {
1011                buf.push(30);
1012            }
1013            &Self::CreateNativeMint => {
1014                buf.push(31);
1015            }
1016            &Self::InitializeNonTransferableMint => {
1017                buf.push(32);
1018            }
1019            &Self::InterestBearingMintExtension => {
1020                buf.push(33);
1021            }
1022            &Self::CpiGuardExtension => {
1023                buf.push(34);
1024            }
1025            Self::InitializePermanentDelegate { delegate } => {
1026                buf.push(35);
1027                buf.extend_from_slice(delegate.as_ref());
1028            }
1029            &Self::TransferHookExtension => {
1030                buf.push(36);
1031            }
1032            &Self::ConfidentialTransferFeeExtension => {
1033                buf.push(37);
1034            }
1035            &Self::WithdrawExcessLamports => {
1036                buf.push(38);
1037            }
1038            &Self::MetadataPointerExtension => {
1039                buf.push(39);
1040            }
1041            &Self::GroupPointerExtension => {
1042                buf.push(40);
1043            }
1044            &Self::GroupMemberPointerExtension => {
1045                buf.push(41);
1046            }
1047            &Self::ConfidentialMintBurnExtension => {
1048                buf.push(42);
1049            }
1050            &Self::ScaledUiAmountExtension => {
1051                buf.push(43);
1052            }
1053            &Self::PausableExtension => {
1054                buf.push(44);
1055            }
1056        };
1057        buf
1058    }
1059
1060    pub(crate) fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
1061        let pk = input
1062            .get(..PUBKEY_BYTES)
1063            .and_then(|x| Pubkey::try_from(x).ok())
1064            .ok_or(TokenError::InvalidInstruction)?;
1065        Ok((pk, &input[PUBKEY_BYTES..]))
1066    }
1067
1068    pub(crate) fn unpack_pubkey_option(
1069        input: &[u8],
1070    ) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
1071        match input.split_first() {
1072            Option::Some((&0, rest)) => Ok((COption::None, rest)),
1073            Option::Some((&1, rest)) => {
1074                let (pk, rest) = Self::unpack_pubkey(rest)?;
1075                Ok((COption::Some(pk), rest))
1076            }
1077            _ => Err(TokenError::InvalidInstruction.into()),
1078        }
1079    }
1080
1081    pub(crate) fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
1082        match *value {
1083            COption::Some(ref key) => {
1084                buf.push(1);
1085                buf.extend_from_slice(&key.to_bytes());
1086            }
1087            COption::None => buf.push(0),
1088        }
1089    }
1090
1091    pub(crate) fn unpack_u16(input: &[u8]) -> Result<(u16, &[u8]), ProgramError> {
1092        let value = input
1093            .get(..U16_BYTES)
1094            .and_then(|slice| slice.try_into().ok())
1095            .map(u16::from_le_bytes)
1096            .ok_or(TokenError::InvalidInstruction)?;
1097        Ok((value, &input[U16_BYTES..]))
1098    }
1099
1100    pub(crate) fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
1101        let value = input
1102            .get(..U64_BYTES)
1103            .and_then(|slice| slice.try_into().ok())
1104            .map(u64::from_le_bytes)
1105            .ok_or(TokenError::InvalidInstruction)?;
1106        Ok((value, &input[U64_BYTES..]))
1107    }
1108
1109    pub(crate) fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> {
1110        let (amount, rest) = Self::unpack_u64(input)?;
1111        let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?;
1112        Ok((amount, decimals, rest))
1113    }
1114}
1115
1116/// Specifies the authority type for `SetAuthority` instructions
1117#[repr(u8)]
1118#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1119#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1120#[derive(Clone, Debug, PartialEq)]
1121pub enum AuthorityType {
1122    /// Authority to mint new tokens
1123    MintTokens,
1124    /// Authority to freeze any account associated with the Mint
1125    FreezeAccount,
1126    /// Owner of a given token account
1127    AccountOwner,
1128    /// Authority to close a token account
1129    CloseAccount,
1130    /// Authority to set the transfer fee
1131    TransferFeeConfig,
1132    /// Authority to withdraw withheld tokens from a mint
1133    WithheldWithdraw,
1134    /// Authority to close a mint account
1135    CloseMint,
1136    /// Authority to set the interest rate
1137    InterestRate,
1138    /// Authority to transfer or burn any tokens for a mint
1139    PermanentDelegate,
1140    /// Authority to update confidential transfer mint and approve accounts for
1141    /// confidential transfers
1142    ConfidentialTransferMint,
1143    /// Authority to set the transfer hook program id
1144    TransferHookProgramId,
1145    /// Authority to set the withdraw withheld authority encryption key
1146    ConfidentialTransferFeeConfig,
1147    /// Authority to set the metadata address
1148    MetadataPointer,
1149    /// Authority to set the group address
1150    GroupPointer,
1151    /// Authority to set the group member address
1152    GroupMemberPointer,
1153    /// Authority to set the UI amount scale
1154    ScaledUiAmount,
1155    /// Authority to pause or resume minting / transferring / burning
1156    Pause,
1157}
1158
1159impl AuthorityType {
1160    fn into(&self) -> u8 {
1161        match self {
1162            AuthorityType::MintTokens => 0,
1163            AuthorityType::FreezeAccount => 1,
1164            AuthorityType::AccountOwner => 2,
1165            AuthorityType::CloseAccount => 3,
1166            AuthorityType::TransferFeeConfig => 4,
1167            AuthorityType::WithheldWithdraw => 5,
1168            AuthorityType::CloseMint => 6,
1169            AuthorityType::InterestRate => 7,
1170            AuthorityType::PermanentDelegate => 8,
1171            AuthorityType::ConfidentialTransferMint => 9,
1172            AuthorityType::TransferHookProgramId => 10,
1173            AuthorityType::ConfidentialTransferFeeConfig => 11,
1174            AuthorityType::MetadataPointer => 12,
1175            AuthorityType::GroupPointer => 13,
1176            AuthorityType::GroupMemberPointer => 14,
1177            AuthorityType::ScaledUiAmount => 15,
1178            AuthorityType::Pause => 16,
1179        }
1180    }
1181
1182    /// Try to convert from a `u8` into the enum
1183    pub fn from(index: u8) -> Result<Self, ProgramError> {
1184        match index {
1185            0 => Ok(AuthorityType::MintTokens),
1186            1 => Ok(AuthorityType::FreezeAccount),
1187            2 => Ok(AuthorityType::AccountOwner),
1188            3 => Ok(AuthorityType::CloseAccount),
1189            4 => Ok(AuthorityType::TransferFeeConfig),
1190            5 => Ok(AuthorityType::WithheldWithdraw),
1191            6 => Ok(AuthorityType::CloseMint),
1192            7 => Ok(AuthorityType::InterestRate),
1193            8 => Ok(AuthorityType::PermanentDelegate),
1194            9 => Ok(AuthorityType::ConfidentialTransferMint),
1195            10 => Ok(AuthorityType::TransferHookProgramId),
1196            11 => Ok(AuthorityType::ConfidentialTransferFeeConfig),
1197            12 => Ok(AuthorityType::MetadataPointer),
1198            13 => Ok(AuthorityType::GroupPointer),
1199            14 => Ok(AuthorityType::GroupMemberPointer),
1200            15 => Ok(AuthorityType::ScaledUiAmount),
1201            16 => Ok(AuthorityType::Pause),
1202            _ => Err(TokenError::InvalidInstruction.into()),
1203        }
1204    }
1205}
1206
1207/// Creates a `InitializeMint` instruction.
1208pub fn initialize_mint(
1209    token_program_id: &Pubkey,
1210    mint_pubkey: &Pubkey,
1211    mint_authority_pubkey: &Pubkey,
1212    freeze_authority_pubkey: Option<&Pubkey>,
1213    decimals: u8,
1214) -> Result<Instruction, ProgramError> {
1215    check_spl_token_program_account(token_program_id)?;
1216    let freeze_authority = freeze_authority_pubkey.cloned().into();
1217    let data = TokenInstruction::InitializeMint {
1218        mint_authority: *mint_authority_pubkey,
1219        freeze_authority,
1220        decimals,
1221    }
1222    .pack();
1223
1224    let accounts = vec![
1225        AccountMeta::new(*mint_pubkey, false),
1226        AccountMeta::new_readonly(sysvar::rent::id(), false),
1227    ];
1228
1229    Ok(Instruction {
1230        program_id: *token_program_id,
1231        accounts,
1232        data,
1233    })
1234}
1235
1236/// Creates a `InitializeMint2` instruction.
1237pub fn initialize_mint2(
1238    token_program_id: &Pubkey,
1239    mint_pubkey: &Pubkey,
1240    mint_authority_pubkey: &Pubkey,
1241    freeze_authority_pubkey: Option<&Pubkey>,
1242    decimals: u8,
1243) -> Result<Instruction, ProgramError> {
1244    check_spl_token_program_account(token_program_id)?;
1245    let freeze_authority = freeze_authority_pubkey.cloned().into();
1246    let data = TokenInstruction::InitializeMint2 {
1247        mint_authority: *mint_authority_pubkey,
1248        freeze_authority,
1249        decimals,
1250    }
1251    .pack();
1252
1253    let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
1254
1255    Ok(Instruction {
1256        program_id: *token_program_id,
1257        accounts,
1258        data,
1259    })
1260}
1261
1262/// Creates a `InitializeAccount` instruction.
1263pub fn initialize_account(
1264    token_program_id: &Pubkey,
1265    account_pubkey: &Pubkey,
1266    mint_pubkey: &Pubkey,
1267    owner_pubkey: &Pubkey,
1268) -> Result<Instruction, ProgramError> {
1269    check_spl_token_program_account(token_program_id)?;
1270    let data = TokenInstruction::InitializeAccount.pack();
1271
1272    let accounts = vec![
1273        AccountMeta::new(*account_pubkey, false),
1274        AccountMeta::new_readonly(*mint_pubkey, false),
1275        AccountMeta::new_readonly(*owner_pubkey, false),
1276        AccountMeta::new_readonly(sysvar::rent::id(), false),
1277    ];
1278
1279    Ok(Instruction {
1280        program_id: *token_program_id,
1281        accounts,
1282        data,
1283    })
1284}
1285
1286/// Creates a `InitializeAccount2` instruction.
1287pub fn initialize_account2(
1288    token_program_id: &Pubkey,
1289    account_pubkey: &Pubkey,
1290    mint_pubkey: &Pubkey,
1291    owner_pubkey: &Pubkey,
1292) -> Result<Instruction, ProgramError> {
1293    check_spl_token_program_account(token_program_id)?;
1294    let data = TokenInstruction::InitializeAccount2 {
1295        owner: *owner_pubkey,
1296    }
1297    .pack();
1298
1299    let accounts = vec![
1300        AccountMeta::new(*account_pubkey, false),
1301        AccountMeta::new_readonly(*mint_pubkey, false),
1302        AccountMeta::new_readonly(sysvar::rent::id(), false),
1303    ];
1304
1305    Ok(Instruction {
1306        program_id: *token_program_id,
1307        accounts,
1308        data,
1309    })
1310}
1311
1312/// Creates a `InitializeAccount3` instruction.
1313pub fn initialize_account3(
1314    token_program_id: &Pubkey,
1315    account_pubkey: &Pubkey,
1316    mint_pubkey: &Pubkey,
1317    owner_pubkey: &Pubkey,
1318) -> Result<Instruction, ProgramError> {
1319    check_spl_token_program_account(token_program_id)?;
1320    let data = TokenInstruction::InitializeAccount3 {
1321        owner: *owner_pubkey,
1322    }
1323    .pack();
1324
1325    let accounts = vec![
1326        AccountMeta::new(*account_pubkey, false),
1327        AccountMeta::new_readonly(*mint_pubkey, false),
1328    ];
1329
1330    Ok(Instruction {
1331        program_id: *token_program_id,
1332        accounts,
1333        data,
1334    })
1335}
1336
1337/// Creates a `InitializeMultisig` instruction.
1338pub fn initialize_multisig(
1339    token_program_id: &Pubkey,
1340    multisig_pubkey: &Pubkey,
1341    signer_pubkeys: &[&Pubkey],
1342    m: u8,
1343) -> Result<Instruction, ProgramError> {
1344    check_spl_token_program_account(token_program_id)?;
1345    if !is_valid_signer_index(m as usize)
1346        || !is_valid_signer_index(signer_pubkeys.len())
1347        || m as usize > signer_pubkeys.len()
1348    {
1349        return Err(ProgramError::MissingRequiredSignature);
1350    }
1351    let data = TokenInstruction::InitializeMultisig { m }.pack();
1352
1353    let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1354    accounts.push(AccountMeta::new(*multisig_pubkey, false));
1355    accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
1356    for signer_pubkey in signer_pubkeys.iter() {
1357        accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1358    }
1359
1360    Ok(Instruction {
1361        program_id: *token_program_id,
1362        accounts,
1363        data,
1364    })
1365}
1366
1367/// Creates a `InitializeMultisig2` instruction.
1368pub fn initialize_multisig2(
1369    token_program_id: &Pubkey,
1370    multisig_pubkey: &Pubkey,
1371    signer_pubkeys: &[&Pubkey],
1372    m: u8,
1373) -> Result<Instruction, ProgramError> {
1374    check_spl_token_program_account(token_program_id)?;
1375    if !is_valid_signer_index(m as usize)
1376        || !is_valid_signer_index(signer_pubkeys.len())
1377        || m as usize > signer_pubkeys.len()
1378    {
1379        return Err(ProgramError::MissingRequiredSignature);
1380    }
1381    let data = TokenInstruction::InitializeMultisig2 { m }.pack();
1382
1383    let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1384    accounts.push(AccountMeta::new(*multisig_pubkey, false));
1385    for signer_pubkey in signer_pubkeys.iter() {
1386        accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1387    }
1388
1389    Ok(Instruction {
1390        program_id: *token_program_id,
1391        accounts,
1392        data,
1393    })
1394}
1395
1396/// Creates a `Transfer` instruction.
1397#[deprecated(
1398    since = "4.0.0",
1399    note = "please use `transfer_checked` or `transfer_checked_with_fee` instead"
1400)]
1401pub fn transfer(
1402    token_program_id: &Pubkey,
1403    source_pubkey: &Pubkey,
1404    destination_pubkey: &Pubkey,
1405    authority_pubkey: &Pubkey,
1406    signer_pubkeys: &[&Pubkey],
1407    amount: u64,
1408) -> Result<Instruction, ProgramError> {
1409    check_spl_token_program_account(token_program_id)?;
1410    #[allow(deprecated)]
1411    let data = TokenInstruction::Transfer { amount }.pack();
1412
1413    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1414    accounts.push(AccountMeta::new(*source_pubkey, false));
1415    accounts.push(AccountMeta::new(*destination_pubkey, false));
1416    accounts.push(AccountMeta::new_readonly(
1417        *authority_pubkey,
1418        signer_pubkeys.is_empty(),
1419    ));
1420    for signer_pubkey in signer_pubkeys.iter() {
1421        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1422    }
1423
1424    Ok(Instruction {
1425        program_id: *token_program_id,
1426        accounts,
1427        data,
1428    })
1429}
1430
1431/// Creates an `Approve` instruction.
1432pub fn approve(
1433    token_program_id: &Pubkey,
1434    source_pubkey: &Pubkey,
1435    delegate_pubkey: &Pubkey,
1436    owner_pubkey: &Pubkey,
1437    signer_pubkeys: &[&Pubkey],
1438    amount: u64,
1439) -> Result<Instruction, ProgramError> {
1440    check_spl_token_program_account(token_program_id)?;
1441    let data = TokenInstruction::Approve { amount }.pack();
1442
1443    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1444    accounts.push(AccountMeta::new(*source_pubkey, false));
1445    accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1446    accounts.push(AccountMeta::new_readonly(
1447        *owner_pubkey,
1448        signer_pubkeys.is_empty(),
1449    ));
1450    for signer_pubkey in signer_pubkeys.iter() {
1451        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1452    }
1453
1454    Ok(Instruction {
1455        program_id: *token_program_id,
1456        accounts,
1457        data,
1458    })
1459}
1460
1461/// Creates a `Revoke` instruction.
1462pub fn revoke(
1463    token_program_id: &Pubkey,
1464    source_pubkey: &Pubkey,
1465    owner_pubkey: &Pubkey,
1466    signer_pubkeys: &[&Pubkey],
1467) -> Result<Instruction, ProgramError> {
1468    check_spl_token_program_account(token_program_id)?;
1469    let data = TokenInstruction::Revoke.pack();
1470
1471    let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
1472    accounts.push(AccountMeta::new(*source_pubkey, false));
1473    accounts.push(AccountMeta::new_readonly(
1474        *owner_pubkey,
1475        signer_pubkeys.is_empty(),
1476    ));
1477    for signer_pubkey in signer_pubkeys.iter() {
1478        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1479    }
1480
1481    Ok(Instruction {
1482        program_id: *token_program_id,
1483        accounts,
1484        data,
1485    })
1486}
1487
1488/// Creates a `SetAuthority` instruction.
1489pub fn set_authority(
1490    token_program_id: &Pubkey,
1491    owned_pubkey: &Pubkey,
1492    new_authority_pubkey: Option<&Pubkey>,
1493    authority_type: AuthorityType,
1494    owner_pubkey: &Pubkey,
1495    signer_pubkeys: &[&Pubkey],
1496) -> Result<Instruction, ProgramError> {
1497    check_spl_token_program_account(token_program_id)?;
1498    let new_authority = new_authority_pubkey.cloned().into();
1499    let data = TokenInstruction::SetAuthority {
1500        authority_type,
1501        new_authority,
1502    }
1503    .pack();
1504
1505    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1506    accounts.push(AccountMeta::new(*owned_pubkey, false));
1507    accounts.push(AccountMeta::new_readonly(
1508        *owner_pubkey,
1509        signer_pubkeys.is_empty(),
1510    ));
1511    for signer_pubkey in signer_pubkeys.iter() {
1512        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1513    }
1514
1515    Ok(Instruction {
1516        program_id: *token_program_id,
1517        accounts,
1518        data,
1519    })
1520}
1521
1522/// Creates a `MintTo` instruction.
1523pub fn mint_to(
1524    token_program_id: &Pubkey,
1525    mint_pubkey: &Pubkey,
1526    account_pubkey: &Pubkey,
1527    mint_authority_pubkey: &Pubkey,
1528    signer_pubkeys: &[&Pubkey],
1529    amount: u64,
1530) -> Result<Instruction, ProgramError> {
1531    check_spl_token_program_account(token_program_id)?;
1532    let data = TokenInstruction::MintTo { amount }.pack();
1533
1534    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1535    accounts.push(AccountMeta::new(*mint_pubkey, false));
1536    accounts.push(AccountMeta::new(*account_pubkey, false));
1537    accounts.push(AccountMeta::new_readonly(
1538        *mint_authority_pubkey,
1539        signer_pubkeys.is_empty(),
1540    ));
1541    for signer_pubkey in signer_pubkeys.iter() {
1542        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1543    }
1544
1545    Ok(Instruction {
1546        program_id: *token_program_id,
1547        accounts,
1548        data,
1549    })
1550}
1551
1552/// Creates a `Burn` instruction.
1553pub fn burn(
1554    token_program_id: &Pubkey,
1555    account_pubkey: &Pubkey,
1556    mint_pubkey: &Pubkey,
1557    authority_pubkey: &Pubkey,
1558    signer_pubkeys: &[&Pubkey],
1559    amount: u64,
1560) -> Result<Instruction, ProgramError> {
1561    check_spl_token_program_account(token_program_id)?;
1562    let data = TokenInstruction::Burn { amount }.pack();
1563
1564    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1565    accounts.push(AccountMeta::new(*account_pubkey, false));
1566    accounts.push(AccountMeta::new(*mint_pubkey, false));
1567    accounts.push(AccountMeta::new_readonly(
1568        *authority_pubkey,
1569        signer_pubkeys.is_empty(),
1570    ));
1571    for signer_pubkey in signer_pubkeys.iter() {
1572        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1573    }
1574
1575    Ok(Instruction {
1576        program_id: *token_program_id,
1577        accounts,
1578        data,
1579    })
1580}
1581
1582/// Creates a `CloseAccount` instruction.
1583pub fn close_account(
1584    token_program_id: &Pubkey,
1585    account_pubkey: &Pubkey,
1586    destination_pubkey: &Pubkey,
1587    owner_pubkey: &Pubkey,
1588    signer_pubkeys: &[&Pubkey],
1589) -> Result<Instruction, ProgramError> {
1590    check_spl_token_program_account(token_program_id)?;
1591    let data = TokenInstruction::CloseAccount.pack();
1592
1593    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1594    accounts.push(AccountMeta::new(*account_pubkey, false));
1595    accounts.push(AccountMeta::new(*destination_pubkey, false));
1596    accounts.push(AccountMeta::new_readonly(
1597        *owner_pubkey,
1598        signer_pubkeys.is_empty(),
1599    ));
1600    for signer_pubkey in signer_pubkeys.iter() {
1601        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1602    }
1603
1604    Ok(Instruction {
1605        program_id: *token_program_id,
1606        accounts,
1607        data,
1608    })
1609}
1610
1611/// Creates a `FreezeAccount` instruction.
1612pub fn freeze_account(
1613    token_program_id: &Pubkey,
1614    account_pubkey: &Pubkey,
1615    mint_pubkey: &Pubkey,
1616    freeze_authority_pubkey: &Pubkey,
1617    signer_pubkeys: &[&Pubkey],
1618) -> Result<Instruction, ProgramError> {
1619    check_spl_token_program_account(token_program_id)?;
1620    let data = TokenInstruction::FreezeAccount.pack();
1621
1622    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1623    accounts.push(AccountMeta::new(*account_pubkey, false));
1624    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1625    accounts.push(AccountMeta::new_readonly(
1626        *freeze_authority_pubkey,
1627        signer_pubkeys.is_empty(),
1628    ));
1629    for signer_pubkey in signer_pubkeys.iter() {
1630        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1631    }
1632
1633    Ok(Instruction {
1634        program_id: *token_program_id,
1635        accounts,
1636        data,
1637    })
1638}
1639
1640/// Creates a `ThawAccount` instruction.
1641pub fn thaw_account(
1642    token_program_id: &Pubkey,
1643    account_pubkey: &Pubkey,
1644    mint_pubkey: &Pubkey,
1645    freeze_authority_pubkey: &Pubkey,
1646    signer_pubkeys: &[&Pubkey],
1647) -> Result<Instruction, ProgramError> {
1648    check_spl_token_program_account(token_program_id)?;
1649    let data = TokenInstruction::ThawAccount.pack();
1650
1651    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1652    accounts.push(AccountMeta::new(*account_pubkey, false));
1653    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1654    accounts.push(AccountMeta::new_readonly(
1655        *freeze_authority_pubkey,
1656        signer_pubkeys.is_empty(),
1657    ));
1658    for signer_pubkey in signer_pubkeys.iter() {
1659        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1660    }
1661
1662    Ok(Instruction {
1663        program_id: *token_program_id,
1664        accounts,
1665        data,
1666    })
1667}
1668
1669/// Creates a `TransferChecked` instruction.
1670#[allow(clippy::too_many_arguments)]
1671pub fn transfer_checked(
1672    token_program_id: &Pubkey,
1673    source_pubkey: &Pubkey,
1674    mint_pubkey: &Pubkey,
1675    destination_pubkey: &Pubkey,
1676    authority_pubkey: &Pubkey,
1677    signer_pubkeys: &[&Pubkey],
1678    amount: u64,
1679    decimals: u8,
1680) -> Result<Instruction, ProgramError> {
1681    check_spl_token_program_account(token_program_id)?;
1682    let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1683
1684    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1685    accounts.push(AccountMeta::new(*source_pubkey, false));
1686    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1687    accounts.push(AccountMeta::new(*destination_pubkey, false));
1688    accounts.push(AccountMeta::new_readonly(
1689        *authority_pubkey,
1690        signer_pubkeys.is_empty(),
1691    ));
1692    for signer_pubkey in signer_pubkeys.iter() {
1693        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1694    }
1695
1696    Ok(Instruction {
1697        program_id: *token_program_id,
1698        accounts,
1699        data,
1700    })
1701}
1702
1703/// Creates an `ApproveChecked` instruction.
1704#[allow(clippy::too_many_arguments)]
1705pub fn approve_checked(
1706    token_program_id: &Pubkey,
1707    source_pubkey: &Pubkey,
1708    mint_pubkey: &Pubkey,
1709    delegate_pubkey: &Pubkey,
1710    owner_pubkey: &Pubkey,
1711    signer_pubkeys: &[&Pubkey],
1712    amount: u64,
1713    decimals: u8,
1714) -> Result<Instruction, ProgramError> {
1715    check_spl_token_program_account(token_program_id)?;
1716    let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1717
1718    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1719    accounts.push(AccountMeta::new(*source_pubkey, false));
1720    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1721    accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1722    accounts.push(AccountMeta::new_readonly(
1723        *owner_pubkey,
1724        signer_pubkeys.is_empty(),
1725    ));
1726    for signer_pubkey in signer_pubkeys.iter() {
1727        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1728    }
1729
1730    Ok(Instruction {
1731        program_id: *token_program_id,
1732        accounts,
1733        data,
1734    })
1735}
1736
1737/// Creates a `MintToChecked` instruction.
1738pub fn mint_to_checked(
1739    token_program_id: &Pubkey,
1740    mint_pubkey: &Pubkey,
1741    account_pubkey: &Pubkey,
1742    mint_authority_pubkey: &Pubkey,
1743    signer_pubkeys: &[&Pubkey],
1744    amount: u64,
1745    decimals: u8,
1746) -> Result<Instruction, ProgramError> {
1747    check_spl_token_program_account(token_program_id)?;
1748    let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1749
1750    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1751    accounts.push(AccountMeta::new(*mint_pubkey, false));
1752    accounts.push(AccountMeta::new(*account_pubkey, false));
1753    accounts.push(AccountMeta::new_readonly(
1754        *mint_authority_pubkey,
1755        signer_pubkeys.is_empty(),
1756    ));
1757    for signer_pubkey in signer_pubkeys.iter() {
1758        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1759    }
1760
1761    Ok(Instruction {
1762        program_id: *token_program_id,
1763        accounts,
1764        data,
1765    })
1766}
1767
1768/// Creates a `BurnChecked` instruction.
1769pub fn burn_checked(
1770    token_program_id: &Pubkey,
1771    account_pubkey: &Pubkey,
1772    mint_pubkey: &Pubkey,
1773    authority_pubkey: &Pubkey,
1774    signer_pubkeys: &[&Pubkey],
1775    amount: u64,
1776    decimals: u8,
1777) -> Result<Instruction, ProgramError> {
1778    check_spl_token_program_account(token_program_id)?;
1779    let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1780
1781    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1782    accounts.push(AccountMeta::new(*account_pubkey, false));
1783    accounts.push(AccountMeta::new(*mint_pubkey, false));
1784    accounts.push(AccountMeta::new_readonly(
1785        *authority_pubkey,
1786        signer_pubkeys.is_empty(),
1787    ));
1788    for signer_pubkey in signer_pubkeys.iter() {
1789        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1790    }
1791
1792    Ok(Instruction {
1793        program_id: *token_program_id,
1794        accounts,
1795        data,
1796    })
1797}
1798
1799/// Creates a `SyncNative` instruction
1800pub fn sync_native(
1801    token_program_id: &Pubkey,
1802    account_pubkey: &Pubkey,
1803) -> Result<Instruction, ProgramError> {
1804    check_spl_token_program_account(token_program_id)?;
1805
1806    Ok(Instruction {
1807        program_id: *token_program_id,
1808        accounts: vec![AccountMeta::new(*account_pubkey, false)],
1809        data: TokenInstruction::SyncNative.pack(),
1810    })
1811}
1812
1813/// Creates a `GetAccountDataSize` instruction
1814pub fn get_account_data_size(
1815    token_program_id: &Pubkey,
1816    mint_pubkey: &Pubkey,
1817    extension_types: &[ExtensionType],
1818) -> Result<Instruction, ProgramError> {
1819    check_spl_token_program_account(token_program_id)?;
1820    Ok(Instruction {
1821        program_id: *token_program_id,
1822        accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1823        data: TokenInstruction::GetAccountDataSize {
1824            extension_types: extension_types.to_vec(),
1825        }
1826        .pack(),
1827    })
1828}
1829
1830/// Creates an `InitializeMintCloseAuthority` instruction
1831pub fn initialize_mint_close_authority(
1832    token_program_id: &Pubkey,
1833    mint_pubkey: &Pubkey,
1834    close_authority: Option<&Pubkey>,
1835) -> Result<Instruction, ProgramError> {
1836    check_program_account(token_program_id)?;
1837    let close_authority = close_authority.cloned().into();
1838    Ok(Instruction {
1839        program_id: *token_program_id,
1840        accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1841        data: TokenInstruction::InitializeMintCloseAuthority { close_authority }.pack(),
1842    })
1843}
1844
1845/// Create an `InitializeImmutableOwner` instruction
1846pub fn initialize_immutable_owner(
1847    token_program_id: &Pubkey,
1848    token_account: &Pubkey,
1849) -> Result<Instruction, ProgramError> {
1850    check_spl_token_program_account(token_program_id)?;
1851    Ok(Instruction {
1852        program_id: *token_program_id,
1853        accounts: vec![AccountMeta::new(*token_account, false)],
1854        data: TokenInstruction::InitializeImmutableOwner.pack(),
1855    })
1856}
1857
1858/// Creates an `AmountToUiAmount` instruction
1859pub fn amount_to_ui_amount(
1860    token_program_id: &Pubkey,
1861    mint_pubkey: &Pubkey,
1862    amount: u64,
1863) -> Result<Instruction, ProgramError> {
1864    check_spl_token_program_account(token_program_id)?;
1865
1866    Ok(Instruction {
1867        program_id: *token_program_id,
1868        accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1869        data: TokenInstruction::AmountToUiAmount { amount }.pack(),
1870    })
1871}
1872
1873/// Creates a `UiAmountToAmount` instruction
1874pub fn ui_amount_to_amount(
1875    token_program_id: &Pubkey,
1876    mint_pubkey: &Pubkey,
1877    ui_amount: &str,
1878) -> Result<Instruction, ProgramError> {
1879    check_spl_token_program_account(token_program_id)?;
1880
1881    Ok(Instruction {
1882        program_id: *token_program_id,
1883        accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1884        data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(),
1885    })
1886}
1887
1888/// Creates a `Reallocate` instruction
1889pub fn reallocate(
1890    token_program_id: &Pubkey,
1891    account_pubkey: &Pubkey,
1892    payer: &Pubkey,
1893    owner_pubkey: &Pubkey,
1894    signer_pubkeys: &[&Pubkey],
1895    extension_types: &[ExtensionType],
1896) -> Result<Instruction, ProgramError> {
1897    check_program_account(token_program_id)?;
1898
1899    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1900    accounts.push(AccountMeta::new(*account_pubkey, false));
1901    accounts.push(AccountMeta::new(*payer, true));
1902    accounts.push(AccountMeta::new_readonly(system_program::id(), false));
1903    accounts.push(AccountMeta::new_readonly(
1904        *owner_pubkey,
1905        signer_pubkeys.is_empty(),
1906    ));
1907    for signer_pubkey in signer_pubkeys.iter() {
1908        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1909    }
1910
1911    Ok(Instruction {
1912        program_id: *token_program_id,
1913        accounts,
1914        data: TokenInstruction::Reallocate {
1915            extension_types: extension_types.to_vec(),
1916        }
1917        .pack(),
1918    })
1919}
1920
1921/// Creates a `CreateNativeMint` instruction
1922pub fn create_native_mint(
1923    token_program_id: &Pubkey,
1924    payer: &Pubkey,
1925) -> Result<Instruction, ProgramError> {
1926    check_program_account(token_program_id)?;
1927
1928    Ok(Instruction {
1929        program_id: *token_program_id,
1930        accounts: vec![
1931            AccountMeta::new(*payer, true),
1932            AccountMeta::new(crate::native_mint::id(), false),
1933            AccountMeta::new_readonly(system_program::id(), false),
1934        ],
1935        data: TokenInstruction::CreateNativeMint.pack(),
1936    })
1937}
1938
1939/// Creates an `InitializeNonTransferableMint` instruction
1940pub fn initialize_non_transferable_mint(
1941    token_program_id: &Pubkey,
1942    mint_pubkey: &Pubkey,
1943) -> Result<Instruction, ProgramError> {
1944    check_program_account(token_program_id)?;
1945    Ok(Instruction {
1946        program_id: *token_program_id,
1947        accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1948        data: TokenInstruction::InitializeNonTransferableMint.pack(),
1949    })
1950}
1951
1952/// Creates an `InitializePermanentDelegate` instruction
1953pub fn initialize_permanent_delegate(
1954    token_program_id: &Pubkey,
1955    mint_pubkey: &Pubkey,
1956    delegate: &Pubkey,
1957) -> Result<Instruction, ProgramError> {
1958    check_program_account(token_program_id)?;
1959    Ok(Instruction {
1960        program_id: *token_program_id,
1961        accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1962        data: TokenInstruction::InitializePermanentDelegate {
1963            delegate: *delegate,
1964        }
1965        .pack(),
1966    })
1967}
1968
1969/// Utility function that checks index is between `MIN_SIGNERS` and
1970/// `MAX_SIGNERS`
1971pub fn is_valid_signer_index(index: usize) -> bool {
1972    (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1973}
1974
1975/// Utility function for decoding just the instruction type
1976pub fn decode_instruction_type<T: TryFrom<u8>>(input: &[u8]) -> Result<T, ProgramError> {
1977    if input.is_empty() {
1978        Err(ProgramError::InvalidInstructionData)
1979    } else {
1980        T::try_from(input[0]).map_err(|_| TokenError::InvalidInstruction.into())
1981    }
1982}
1983
1984/// Utility function for decoding instruction data
1985///
1986/// Note: This function expects the entire instruction input, including the
1987/// instruction type as the first byte.  This makes the code concise and safe
1988/// at the expense of clarity, allowing flows such as:
1989///
1990/// ```
1991/// use spl_token_2022_interface::instruction::{decode_instruction_data, decode_instruction_type};
1992/// use num_enum::TryFromPrimitive;
1993/// use bytemuck::{Pod, Zeroable};
1994///
1995/// #[repr(u8)]
1996/// #[derive(Clone, Copy, TryFromPrimitive)]
1997/// enum InstructionType {
1998///     First
1999/// }
2000/// #[derive(Pod, Zeroable, Copy, Clone)]
2001/// #[repr(transparent)]
2002/// struct FirstData {
2003///     a: u8,
2004/// }
2005/// let input = [0, 1];
2006/// match decode_instruction_type(&input).unwrap() {
2007///     InstructionType::First => {
2008///         let FirstData { a } = decode_instruction_data(&input).unwrap();
2009///         assert_eq!(*a, 1);
2010///     }
2011/// }
2012/// ```
2013pub fn decode_instruction_data<T: Pod>(input_with_type: &[u8]) -> Result<&T, ProgramError> {
2014    if input_with_type.len() != pod_get_packed_len::<T>().saturating_add(1) {
2015        Err(ProgramError::InvalidInstructionData)
2016    } else {
2017        pod_from_bytes(&input_with_type[1..])
2018    }
2019}
2020
2021/// Utility function for encoding instruction data
2022pub(crate) fn encode_instruction<T: Into<u8>, D: Pod>(
2023    token_program_id: &Pubkey,
2024    accounts: Vec<AccountMeta>,
2025    token_instruction_type: TokenInstruction,
2026    instruction_type: T,
2027    instruction_data: &D,
2028) -> Instruction {
2029    let mut data = token_instruction_type.pack();
2030    data.push(T::into(instruction_type));
2031    data.extend_from_slice(bytemuck::bytes_of(instruction_data));
2032    Instruction {
2033        program_id: *token_program_id,
2034        accounts,
2035        data,
2036    }
2037}
2038
2039/// Creates a `WithdrawExcessLamports` Instruction
2040pub fn withdraw_excess_lamports(
2041    token_program_id: &Pubkey,
2042    source_account: &Pubkey,
2043    destination_account: &Pubkey,
2044    authority: &Pubkey,
2045    signers: &[&Pubkey],
2046) -> Result<Instruction, ProgramError> {
2047    check_program_account(token_program_id)?;
2048
2049    let mut accounts = vec![
2050        AccountMeta::new(*source_account, false),
2051        AccountMeta::new(*destination_account, false),
2052        AccountMeta::new_readonly(*authority, signers.is_empty()),
2053    ];
2054
2055    for signer in signers {
2056        accounts.push(AccountMeta::new_readonly(**signer, true))
2057    }
2058
2059    Ok(Instruction {
2060        program_id: *token_program_id,
2061        accounts,
2062        data: TokenInstruction::WithdrawExcessLamports.pack(),
2063    })
2064}
2065
2066#[cfg(test)]
2067mod test {
2068    use {super::*, proptest::prelude::*};
2069
2070    #[test]
2071    fn test_initialize_mint_packing() {
2072        let decimals = 2;
2073        let mint_authority = Pubkey::new_from_array([1u8; 32]);
2074        let freeze_authority = COption::None;
2075        let check = TokenInstruction::InitializeMint {
2076            decimals,
2077            mint_authority,
2078            freeze_authority,
2079        };
2080        let packed = check.pack();
2081        let mut expect = Vec::from([0u8, 2]);
2082        expect.extend_from_slice(&[1u8; 32]);
2083        expect.extend_from_slice(&[0]);
2084        assert_eq!(packed, expect);
2085        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2086        assert_eq!(unpacked, check);
2087
2088        let mint_authority = Pubkey::new_from_array([2u8; 32]);
2089        let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2090        let check = TokenInstruction::InitializeMint {
2091            decimals,
2092            mint_authority,
2093            freeze_authority,
2094        };
2095        let packed = check.pack();
2096        let mut expect = vec![0u8, 2];
2097        expect.extend_from_slice(&[2u8; 32]);
2098        expect.extend_from_slice(&[1]);
2099        expect.extend_from_slice(&[3u8; 32]);
2100        assert_eq!(packed, expect);
2101        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2102        assert_eq!(unpacked, check);
2103    }
2104
2105    #[test]
2106    fn test_initialize_account_packing() {
2107        let check = TokenInstruction::InitializeAccount;
2108        let packed = check.pack();
2109        let expect = Vec::from([1u8]);
2110        assert_eq!(packed, expect);
2111        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2112        assert_eq!(unpacked, check);
2113    }
2114
2115    #[test]
2116    fn test_initialize_multisig_packing() {
2117        let m = 1;
2118        let check = TokenInstruction::InitializeMultisig { m };
2119        let packed = check.pack();
2120        let expect = Vec::from([2u8, 1]);
2121        assert_eq!(packed, expect);
2122        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2123        assert_eq!(unpacked, check);
2124    }
2125
2126    #[test]
2127    fn test_transfer_packing() {
2128        let amount = 1;
2129        #[allow(deprecated)]
2130        let check = TokenInstruction::Transfer { amount };
2131        let packed = check.pack();
2132        let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2133        assert_eq!(packed, expect);
2134        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2135        assert_eq!(unpacked, check);
2136    }
2137
2138    #[test]
2139    fn test_approve_packing() {
2140        let amount = 1;
2141        let check = TokenInstruction::Approve { amount };
2142        let packed = check.pack();
2143        let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2144        assert_eq!(packed, expect);
2145        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2146        assert_eq!(unpacked, check);
2147    }
2148
2149    #[test]
2150    fn test_revoke_packing() {
2151        let check = TokenInstruction::Revoke;
2152        let packed = check.pack();
2153        let expect = Vec::from([5u8]);
2154        assert_eq!(packed, expect);
2155        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2156        assert_eq!(unpacked, check);
2157    }
2158
2159    #[test]
2160    fn test_set_authority_packing() {
2161        let authority_type = AuthorityType::FreezeAccount;
2162        let new_authority = COption::Some(Pubkey::new_from_array([4u8; 32]));
2163        let check = TokenInstruction::SetAuthority {
2164            authority_type: authority_type.clone(),
2165            new_authority,
2166        };
2167        let packed = check.pack();
2168        let mut expect = Vec::from([6u8, 1]);
2169        expect.extend_from_slice(&[1]);
2170        expect.extend_from_slice(&[4u8; 32]);
2171        assert_eq!(packed, expect);
2172        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2173        assert_eq!(unpacked, check);
2174    }
2175
2176    #[test]
2177    fn test_mint_to_packing() {
2178        let amount = 1;
2179        let check = TokenInstruction::MintTo { amount };
2180        let packed = check.pack();
2181        let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2182        assert_eq!(packed, expect);
2183        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2184        assert_eq!(unpacked, check);
2185    }
2186
2187    #[test]
2188    fn test_burn_packing() {
2189        let amount = 1;
2190        let check = TokenInstruction::Burn { amount };
2191        let packed = check.pack();
2192        let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2193        assert_eq!(packed, expect);
2194        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2195        assert_eq!(unpacked, check);
2196    }
2197
2198    #[test]
2199    fn test_close_account_packing() {
2200        let check = TokenInstruction::CloseAccount;
2201        let packed = check.pack();
2202        let expect = Vec::from([9u8]);
2203        assert_eq!(packed, expect);
2204        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2205        assert_eq!(unpacked, check);
2206    }
2207
2208    #[test]
2209    fn test_freeze_account_packing() {
2210        let check = TokenInstruction::FreezeAccount;
2211        let packed = check.pack();
2212        let expect = Vec::from([10u8]);
2213        assert_eq!(packed, expect);
2214        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2215        assert_eq!(unpacked, check);
2216    }
2217
2218    #[test]
2219    fn test_thaw_account_packing() {
2220        let check = TokenInstruction::ThawAccount;
2221        let packed = check.pack();
2222        let expect = Vec::from([11u8]);
2223        assert_eq!(packed, expect);
2224        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2225        assert_eq!(unpacked, check);
2226    }
2227
2228    #[test]
2229    fn test_transfer_checked_packing() {
2230        let amount = 1;
2231        let decimals = 2;
2232        let check = TokenInstruction::TransferChecked { amount, decimals };
2233        let packed = check.pack();
2234        let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2235        assert_eq!(packed, expect);
2236        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2237        assert_eq!(unpacked, check);
2238    }
2239
2240    #[test]
2241    fn test_approve_checked_packing() {
2242        let amount = 1;
2243        let decimals = 2;
2244
2245        let check = TokenInstruction::ApproveChecked { amount, decimals };
2246        let packed = check.pack();
2247        let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2248        assert_eq!(packed, expect);
2249        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2250        assert_eq!(unpacked, check);
2251    }
2252
2253    #[test]
2254    fn test_mint_to_checked_packing() {
2255        let amount = 1;
2256        let decimals = 2;
2257        let check = TokenInstruction::MintToChecked { amount, decimals };
2258        let packed = check.pack();
2259        let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2260        assert_eq!(packed, expect);
2261        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2262        assert_eq!(unpacked, check);
2263    }
2264
2265    #[test]
2266    fn test_burn_checked_packing() {
2267        let amount = 1;
2268        let decimals = 2;
2269        let check = TokenInstruction::BurnChecked { amount, decimals };
2270        let packed = check.pack();
2271        let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2272        assert_eq!(packed, expect);
2273        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2274        assert_eq!(unpacked, check);
2275    }
2276
2277    #[test]
2278    fn test_initialize_account2_packing() {
2279        let owner = Pubkey::new_from_array([2u8; 32]);
2280        let check = TokenInstruction::InitializeAccount2 { owner };
2281        let packed = check.pack();
2282        let mut expect = vec![16u8];
2283        expect.extend_from_slice(&[2u8; 32]);
2284        assert_eq!(packed, expect);
2285        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2286        assert_eq!(unpacked, check);
2287    }
2288
2289    #[test]
2290    fn test_sync_native_packing() {
2291        let check = TokenInstruction::SyncNative;
2292        let packed = check.pack();
2293        let expect = vec![17u8];
2294        assert_eq!(packed, expect);
2295        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2296        assert_eq!(unpacked, check);
2297    }
2298
2299    #[test]
2300    fn test_initialize_account3_packing() {
2301        let owner = Pubkey::new_from_array([2u8; 32]);
2302        let check = TokenInstruction::InitializeAccount3 { owner };
2303        let packed = check.pack();
2304        let mut expect = vec![18u8];
2305        expect.extend_from_slice(&[2u8; 32]);
2306        assert_eq!(packed, expect);
2307        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2308        assert_eq!(unpacked, check);
2309    }
2310
2311    #[test]
2312    fn test_initialize_multisig2_packing() {
2313        let m = 1;
2314        let check = TokenInstruction::InitializeMultisig2 { m };
2315        let packed = check.pack();
2316        let expect = Vec::from([19u8, 1]);
2317        assert_eq!(packed, expect);
2318        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2319        assert_eq!(unpacked, check);
2320    }
2321
2322    #[test]
2323    fn test_initialize_mint2_packing() {
2324        let decimals = 2;
2325        let mint_authority = Pubkey::new_from_array([1u8; 32]);
2326        let freeze_authority = COption::None;
2327        let check = TokenInstruction::InitializeMint2 {
2328            decimals,
2329            mint_authority,
2330            freeze_authority,
2331        };
2332        let packed = check.pack();
2333        let mut expect = Vec::from([20u8, 2]);
2334        expect.extend_from_slice(&[1u8; 32]);
2335        expect.extend_from_slice(&[0]);
2336        assert_eq!(packed, expect);
2337        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2338        assert_eq!(unpacked, check);
2339
2340        let decimals = 2;
2341        let mint_authority = Pubkey::new_from_array([2u8; 32]);
2342        let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2343        let check = TokenInstruction::InitializeMint2 {
2344            decimals,
2345            mint_authority,
2346            freeze_authority,
2347        };
2348        let packed = check.pack();
2349        let mut expect = vec![20u8, 2];
2350        expect.extend_from_slice(&[2u8; 32]);
2351        expect.extend_from_slice(&[1]);
2352        expect.extend_from_slice(&[3u8; 32]);
2353        assert_eq!(packed, expect);
2354        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2355        assert_eq!(unpacked, check);
2356    }
2357
2358    #[test]
2359    fn test_get_account_data_size_packing() {
2360        let extension_types = vec![];
2361        let check = TokenInstruction::GetAccountDataSize {
2362            extension_types: extension_types.clone(),
2363        };
2364        let packed = check.pack();
2365        let expect = [21u8];
2366        assert_eq!(packed, &[21u8]);
2367        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2368        assert_eq!(unpacked, check);
2369
2370        let extension_types = vec![
2371            ExtensionType::TransferFeeConfig,
2372            ExtensionType::TransferFeeAmount,
2373        ];
2374        let check = TokenInstruction::GetAccountDataSize {
2375            extension_types: extension_types.clone(),
2376        };
2377        let packed = check.pack();
2378        let expect = [21u8, 1, 0, 2, 0];
2379        assert_eq!(packed, &[21u8, 1, 0, 2, 0]);
2380        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2381        assert_eq!(unpacked, check);
2382    }
2383
2384    #[test]
2385    fn test_amount_to_ui_amount_packing() {
2386        let amount = 42;
2387        let check = TokenInstruction::AmountToUiAmount { amount };
2388        let packed = check.pack();
2389        let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0];
2390        assert_eq!(packed, expect);
2391        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2392        assert_eq!(unpacked, check);
2393    }
2394
2395    #[test]
2396    fn test_ui_amount_to_amount_packing() {
2397        let ui_amount = "0.42";
2398        let check = TokenInstruction::UiAmountToAmount { ui_amount };
2399        let packed = check.pack();
2400        let expect = vec![24u8, 48, 46, 52, 50];
2401        assert_eq!(packed, expect);
2402        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2403        assert_eq!(unpacked, check);
2404    }
2405
2406    #[test]
2407    fn test_initialize_mint_close_authority_packing() {
2408        let close_authority = COption::Some(Pubkey::new_from_array([10u8; 32]));
2409        let check = TokenInstruction::InitializeMintCloseAuthority { close_authority };
2410        let packed = check.pack();
2411        let mut expect = vec![25u8, 1];
2412        expect.extend_from_slice(&[10u8; 32]);
2413        assert_eq!(packed, expect);
2414        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2415        assert_eq!(unpacked, check);
2416    }
2417
2418    #[test]
2419    fn test_create_native_mint_packing() {
2420        let check = TokenInstruction::CreateNativeMint;
2421        let packed = check.pack();
2422        let expect = vec![31u8];
2423        assert_eq!(packed, expect);
2424        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2425        assert_eq!(unpacked, check);
2426    }
2427
2428    #[test]
2429    fn test_initialize_permanent_delegate_packing() {
2430        let delegate = Pubkey::new_from_array([11u8; 32]);
2431        let check = TokenInstruction::InitializePermanentDelegate { delegate };
2432        let packed = check.pack();
2433        let mut expect = vec![35u8];
2434        expect.extend_from_slice(&[11u8; 32]);
2435        assert_eq!(packed, expect);
2436        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2437        assert_eq!(unpacked, check);
2438    }
2439
2440    macro_rules! test_instruction {
2441        ($a:ident($($b:tt)*)) => {
2442            let instruction_v3 = spl_token_interface::instruction::$a($($b)*).unwrap();
2443            let instruction_2022 = $a($($b)*).unwrap();
2444            assert_eq!(instruction_v3, instruction_2022);
2445        }
2446    }
2447
2448    #[test]
2449    fn test_v3_compatibility() {
2450        let token_program_id = spl_token_interface::id();
2451        let mint_pubkey = Pubkey::new_unique();
2452        let mint_authority_pubkey = Pubkey::new_unique();
2453        let freeze_authority_pubkey = Pubkey::new_unique();
2454        let decimals = 9u8;
2455
2456        let account_pubkey = Pubkey::new_unique();
2457        let owner_pubkey = Pubkey::new_unique();
2458
2459        let multisig_pubkey = Pubkey::new_unique();
2460        let signer_pubkeys_vec = vec![Pubkey::new_unique(); MAX_SIGNERS];
2461        let signer_pubkeys = signer_pubkeys_vec.iter().collect::<Vec<_>>();
2462        let m = 10u8;
2463
2464        let source_pubkey = Pubkey::new_unique();
2465        let destination_pubkey = Pubkey::new_unique();
2466        let authority_pubkey = Pubkey::new_unique();
2467        let amount = 1_000_000_000_000;
2468
2469        let delegate_pubkey = Pubkey::new_unique();
2470        let owned_pubkey = Pubkey::new_unique();
2471        let new_authority_pubkey = Pubkey::new_unique();
2472
2473        let ui_amount = "100000.00";
2474
2475        test_instruction!(initialize_mint(
2476            &token_program_id,
2477            &mint_pubkey,
2478            &mint_authority_pubkey,
2479            None,
2480            decimals,
2481        ));
2482        test_instruction!(initialize_mint2(
2483            &token_program_id,
2484            &mint_pubkey,
2485            &mint_authority_pubkey,
2486            Some(&freeze_authority_pubkey),
2487            decimals,
2488        ));
2489
2490        test_instruction!(initialize_account(
2491            &token_program_id,
2492            &account_pubkey,
2493            &mint_pubkey,
2494            &owner_pubkey,
2495        ));
2496        test_instruction!(initialize_account2(
2497            &token_program_id,
2498            &account_pubkey,
2499            &mint_pubkey,
2500            &owner_pubkey,
2501        ));
2502        test_instruction!(initialize_account3(
2503            &token_program_id,
2504            &account_pubkey,
2505            &mint_pubkey,
2506            &owner_pubkey,
2507        ));
2508        test_instruction!(initialize_multisig(
2509            &token_program_id,
2510            &multisig_pubkey,
2511            &signer_pubkeys,
2512            m,
2513        ));
2514        test_instruction!(initialize_multisig2(
2515            &token_program_id,
2516            &multisig_pubkey,
2517            &signer_pubkeys,
2518            m,
2519        ));
2520        #[allow(deprecated)]
2521        {
2522            test_instruction!(transfer(
2523                &token_program_id,
2524                &source_pubkey,
2525                &destination_pubkey,
2526                &authority_pubkey,
2527                &signer_pubkeys,
2528                amount
2529            ));
2530        }
2531        test_instruction!(transfer_checked(
2532            &token_program_id,
2533            &source_pubkey,
2534            &mint_pubkey,
2535            &destination_pubkey,
2536            &authority_pubkey,
2537            &signer_pubkeys,
2538            amount,
2539            decimals,
2540        ));
2541        test_instruction!(approve(
2542            &token_program_id,
2543            &source_pubkey,
2544            &delegate_pubkey,
2545            &owner_pubkey,
2546            &signer_pubkeys,
2547            amount
2548        ));
2549        test_instruction!(approve_checked(
2550            &token_program_id,
2551            &source_pubkey,
2552            &mint_pubkey,
2553            &delegate_pubkey,
2554            &owner_pubkey,
2555            &signer_pubkeys,
2556            amount,
2557            decimals
2558        ));
2559        test_instruction!(revoke(
2560            &token_program_id,
2561            &source_pubkey,
2562            &owner_pubkey,
2563            &signer_pubkeys,
2564        ));
2565
2566        // set_authority
2567        {
2568            let instruction_v3 = spl_token_interface::instruction::set_authority(
2569                &token_program_id,
2570                &owned_pubkey,
2571                Some(&new_authority_pubkey),
2572                spl_token_interface::instruction::AuthorityType::AccountOwner,
2573                &owner_pubkey,
2574                &signer_pubkeys,
2575            )
2576            .unwrap();
2577            let instruction_2022 = set_authority(
2578                &token_program_id,
2579                &owned_pubkey,
2580                Some(&new_authority_pubkey),
2581                AuthorityType::AccountOwner,
2582                &owner_pubkey,
2583                &signer_pubkeys,
2584            )
2585            .unwrap();
2586            assert_eq!(instruction_v3, instruction_2022);
2587        }
2588
2589        test_instruction!(mint_to(
2590            &token_program_id,
2591            &mint_pubkey,
2592            &account_pubkey,
2593            &owner_pubkey,
2594            &signer_pubkeys,
2595            amount,
2596        ));
2597        test_instruction!(mint_to_checked(
2598            &token_program_id,
2599            &mint_pubkey,
2600            &account_pubkey,
2601            &owner_pubkey,
2602            &signer_pubkeys,
2603            amount,
2604            decimals,
2605        ));
2606        test_instruction!(burn(
2607            &token_program_id,
2608            &account_pubkey,
2609            &mint_pubkey,
2610            &authority_pubkey,
2611            &signer_pubkeys,
2612            amount,
2613        ));
2614        test_instruction!(burn_checked(
2615            &token_program_id,
2616            &account_pubkey,
2617            &mint_pubkey,
2618            &authority_pubkey,
2619            &signer_pubkeys,
2620            amount,
2621            decimals,
2622        ));
2623        test_instruction!(close_account(
2624            &token_program_id,
2625            &account_pubkey,
2626            &destination_pubkey,
2627            &owner_pubkey,
2628            &signer_pubkeys,
2629        ));
2630        test_instruction!(freeze_account(
2631            &token_program_id,
2632            &account_pubkey,
2633            &mint_pubkey,
2634            &freeze_authority_pubkey,
2635            &signer_pubkeys,
2636        ));
2637        test_instruction!(thaw_account(
2638            &token_program_id,
2639            &account_pubkey,
2640            &mint_pubkey,
2641            &freeze_authority_pubkey,
2642            &signer_pubkeys,
2643        ));
2644        test_instruction!(sync_native(&token_program_id, &account_pubkey,));
2645
2646        // get_account_data_size
2647        {
2648            let instruction_v3 = spl_token_interface::instruction::get_account_data_size(
2649                &token_program_id,
2650                &mint_pubkey,
2651            )
2652            .unwrap();
2653            let instruction_2022 =
2654                get_account_data_size(&token_program_id, &mint_pubkey, &[]).unwrap();
2655            assert_eq!(instruction_v3, instruction_2022);
2656        }
2657
2658        test_instruction!(initialize_immutable_owner(
2659            &token_program_id,
2660            &account_pubkey,
2661        ));
2662
2663        test_instruction!(amount_to_ui_amount(&token_program_id, &mint_pubkey, amount,));
2664
2665        test_instruction!(ui_amount_to_amount(
2666            &token_program_id,
2667            &mint_pubkey,
2668            ui_amount,
2669        ));
2670    }
2671
2672    proptest! {
2673        #![proptest_config(ProptestConfig::with_cases(1024))]
2674        #[test]
2675        fn test_instruction_unpack_proptest(
2676            data in prop::collection::vec(any::<u8>(), 0..255)
2677        ) {
2678            let _no_panic = TokenInstruction::unpack(&data);
2679        }
2680    }
2681}