spl_token_2022/
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-traits")]
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-traits", derive(Serialize, Deserialize))]
43#[cfg_attr(
44    feature = "serde-traits",
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-traits", serde(with = "As::<DisplayFromStr>"))]
70        mint_authority: Pubkey,
71        /// The freeze authority/multisignature of the mint.
72        #[cfg_attr(feature = "serde-traits", 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-traits", 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-traits", 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-traits", 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-traits", serde(with = "As::<DisplayFromStr>"))]
482        mint_authority: Pubkey,
483        /// The freeze authority/multisignature of the mint.
484        #[cfg_attr(feature = "serde-traits", 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-traits", 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-traits", 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-traits", derive(Serialize, Deserialize))]
1119#[cfg_attr(feature = "serde-traits", 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    pub(crate) fn from(index: u8) -> Result<Self, ProgramError> {
1183        match index {
1184            0 => Ok(AuthorityType::MintTokens),
1185            1 => Ok(AuthorityType::FreezeAccount),
1186            2 => Ok(AuthorityType::AccountOwner),
1187            3 => Ok(AuthorityType::CloseAccount),
1188            4 => Ok(AuthorityType::TransferFeeConfig),
1189            5 => Ok(AuthorityType::WithheldWithdraw),
1190            6 => Ok(AuthorityType::CloseMint),
1191            7 => Ok(AuthorityType::InterestRate),
1192            8 => Ok(AuthorityType::PermanentDelegate),
1193            9 => Ok(AuthorityType::ConfidentialTransferMint),
1194            10 => Ok(AuthorityType::TransferHookProgramId),
1195            11 => Ok(AuthorityType::ConfidentialTransferFeeConfig),
1196            12 => Ok(AuthorityType::MetadataPointer),
1197            13 => Ok(AuthorityType::GroupPointer),
1198            14 => Ok(AuthorityType::GroupMemberPointer),
1199            15 => Ok(AuthorityType::ScaledUiAmount),
1200            16 => Ok(AuthorityType::Pause),
1201            _ => Err(TokenError::InvalidInstruction.into()),
1202        }
1203    }
1204}
1205
1206/// Creates a `InitializeMint` instruction.
1207pub fn initialize_mint(
1208    token_program_id: &Pubkey,
1209    mint_pubkey: &Pubkey,
1210    mint_authority_pubkey: &Pubkey,
1211    freeze_authority_pubkey: Option<&Pubkey>,
1212    decimals: u8,
1213) -> Result<Instruction, ProgramError> {
1214    check_spl_token_program_account(token_program_id)?;
1215    let freeze_authority = freeze_authority_pubkey.cloned().into();
1216    let data = TokenInstruction::InitializeMint {
1217        mint_authority: *mint_authority_pubkey,
1218        freeze_authority,
1219        decimals,
1220    }
1221    .pack();
1222
1223    let accounts = vec![
1224        AccountMeta::new(*mint_pubkey, false),
1225        AccountMeta::new_readonly(sysvar::rent::id(), false),
1226    ];
1227
1228    Ok(Instruction {
1229        program_id: *token_program_id,
1230        accounts,
1231        data,
1232    })
1233}
1234
1235/// Creates a `InitializeMint2` instruction.
1236pub fn initialize_mint2(
1237    token_program_id: &Pubkey,
1238    mint_pubkey: &Pubkey,
1239    mint_authority_pubkey: &Pubkey,
1240    freeze_authority_pubkey: Option<&Pubkey>,
1241    decimals: u8,
1242) -> Result<Instruction, ProgramError> {
1243    check_spl_token_program_account(token_program_id)?;
1244    let freeze_authority = freeze_authority_pubkey.cloned().into();
1245    let data = TokenInstruction::InitializeMint2 {
1246        mint_authority: *mint_authority_pubkey,
1247        freeze_authority,
1248        decimals,
1249    }
1250    .pack();
1251
1252    let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
1253
1254    Ok(Instruction {
1255        program_id: *token_program_id,
1256        accounts,
1257        data,
1258    })
1259}
1260
1261/// Creates a `InitializeAccount` instruction.
1262pub fn initialize_account(
1263    token_program_id: &Pubkey,
1264    account_pubkey: &Pubkey,
1265    mint_pubkey: &Pubkey,
1266    owner_pubkey: &Pubkey,
1267) -> Result<Instruction, ProgramError> {
1268    check_spl_token_program_account(token_program_id)?;
1269    let data = TokenInstruction::InitializeAccount.pack();
1270
1271    let accounts = vec![
1272        AccountMeta::new(*account_pubkey, false),
1273        AccountMeta::new_readonly(*mint_pubkey, false),
1274        AccountMeta::new_readonly(*owner_pubkey, false),
1275        AccountMeta::new_readonly(sysvar::rent::id(), false),
1276    ];
1277
1278    Ok(Instruction {
1279        program_id: *token_program_id,
1280        accounts,
1281        data,
1282    })
1283}
1284
1285/// Creates a `InitializeAccount2` instruction.
1286pub fn initialize_account2(
1287    token_program_id: &Pubkey,
1288    account_pubkey: &Pubkey,
1289    mint_pubkey: &Pubkey,
1290    owner_pubkey: &Pubkey,
1291) -> Result<Instruction, ProgramError> {
1292    check_spl_token_program_account(token_program_id)?;
1293    let data = TokenInstruction::InitializeAccount2 {
1294        owner: *owner_pubkey,
1295    }
1296    .pack();
1297
1298    let accounts = vec![
1299        AccountMeta::new(*account_pubkey, false),
1300        AccountMeta::new_readonly(*mint_pubkey, false),
1301        AccountMeta::new_readonly(sysvar::rent::id(), false),
1302    ];
1303
1304    Ok(Instruction {
1305        program_id: *token_program_id,
1306        accounts,
1307        data,
1308    })
1309}
1310
1311/// Creates a `InitializeAccount3` instruction.
1312pub fn initialize_account3(
1313    token_program_id: &Pubkey,
1314    account_pubkey: &Pubkey,
1315    mint_pubkey: &Pubkey,
1316    owner_pubkey: &Pubkey,
1317) -> Result<Instruction, ProgramError> {
1318    check_spl_token_program_account(token_program_id)?;
1319    let data = TokenInstruction::InitializeAccount3 {
1320        owner: *owner_pubkey,
1321    }
1322    .pack();
1323
1324    let accounts = vec![
1325        AccountMeta::new(*account_pubkey, false),
1326        AccountMeta::new_readonly(*mint_pubkey, false),
1327    ];
1328
1329    Ok(Instruction {
1330        program_id: *token_program_id,
1331        accounts,
1332        data,
1333    })
1334}
1335
1336/// Creates a `InitializeMultisig` instruction.
1337pub fn initialize_multisig(
1338    token_program_id: &Pubkey,
1339    multisig_pubkey: &Pubkey,
1340    signer_pubkeys: &[&Pubkey],
1341    m: u8,
1342) -> Result<Instruction, ProgramError> {
1343    check_spl_token_program_account(token_program_id)?;
1344    if !is_valid_signer_index(m as usize)
1345        || !is_valid_signer_index(signer_pubkeys.len())
1346        || m as usize > signer_pubkeys.len()
1347    {
1348        return Err(ProgramError::MissingRequiredSignature);
1349    }
1350    let data = TokenInstruction::InitializeMultisig { m }.pack();
1351
1352    let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1353    accounts.push(AccountMeta::new(*multisig_pubkey, false));
1354    accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
1355    for signer_pubkey in signer_pubkeys.iter() {
1356        accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1357    }
1358
1359    Ok(Instruction {
1360        program_id: *token_program_id,
1361        accounts,
1362        data,
1363    })
1364}
1365
1366/// Creates a `InitializeMultisig2` instruction.
1367pub fn initialize_multisig2(
1368    token_program_id: &Pubkey,
1369    multisig_pubkey: &Pubkey,
1370    signer_pubkeys: &[&Pubkey],
1371    m: u8,
1372) -> Result<Instruction, ProgramError> {
1373    check_spl_token_program_account(token_program_id)?;
1374    if !is_valid_signer_index(m as usize)
1375        || !is_valid_signer_index(signer_pubkeys.len())
1376        || m as usize > signer_pubkeys.len()
1377    {
1378        return Err(ProgramError::MissingRequiredSignature);
1379    }
1380    let data = TokenInstruction::InitializeMultisig2 { m }.pack();
1381
1382    let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
1383    accounts.push(AccountMeta::new(*multisig_pubkey, false));
1384    for signer_pubkey in signer_pubkeys.iter() {
1385        accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
1386    }
1387
1388    Ok(Instruction {
1389        program_id: *token_program_id,
1390        accounts,
1391        data,
1392    })
1393}
1394
1395/// Creates a `Transfer` instruction.
1396#[deprecated(
1397    since = "4.0.0",
1398    note = "please use `transfer_checked` or `transfer_checked_with_fee` instead"
1399)]
1400pub fn transfer(
1401    token_program_id: &Pubkey,
1402    source_pubkey: &Pubkey,
1403    destination_pubkey: &Pubkey,
1404    authority_pubkey: &Pubkey,
1405    signer_pubkeys: &[&Pubkey],
1406    amount: u64,
1407) -> Result<Instruction, ProgramError> {
1408    check_spl_token_program_account(token_program_id)?;
1409    #[allow(deprecated)]
1410    let data = TokenInstruction::Transfer { amount }.pack();
1411
1412    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1413    accounts.push(AccountMeta::new(*source_pubkey, false));
1414    accounts.push(AccountMeta::new(*destination_pubkey, false));
1415    accounts.push(AccountMeta::new_readonly(
1416        *authority_pubkey,
1417        signer_pubkeys.is_empty(),
1418    ));
1419    for signer_pubkey in signer_pubkeys.iter() {
1420        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1421    }
1422
1423    Ok(Instruction {
1424        program_id: *token_program_id,
1425        accounts,
1426        data,
1427    })
1428}
1429
1430/// Creates an `Approve` instruction.
1431pub fn approve(
1432    token_program_id: &Pubkey,
1433    source_pubkey: &Pubkey,
1434    delegate_pubkey: &Pubkey,
1435    owner_pubkey: &Pubkey,
1436    signer_pubkeys: &[&Pubkey],
1437    amount: u64,
1438) -> Result<Instruction, ProgramError> {
1439    check_spl_token_program_account(token_program_id)?;
1440    let data = TokenInstruction::Approve { amount }.pack();
1441
1442    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1443    accounts.push(AccountMeta::new(*source_pubkey, false));
1444    accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1445    accounts.push(AccountMeta::new_readonly(
1446        *owner_pubkey,
1447        signer_pubkeys.is_empty(),
1448    ));
1449    for signer_pubkey in signer_pubkeys.iter() {
1450        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1451    }
1452
1453    Ok(Instruction {
1454        program_id: *token_program_id,
1455        accounts,
1456        data,
1457    })
1458}
1459
1460/// Creates a `Revoke` instruction.
1461pub fn revoke(
1462    token_program_id: &Pubkey,
1463    source_pubkey: &Pubkey,
1464    owner_pubkey: &Pubkey,
1465    signer_pubkeys: &[&Pubkey],
1466) -> Result<Instruction, ProgramError> {
1467    check_spl_token_program_account(token_program_id)?;
1468    let data = TokenInstruction::Revoke.pack();
1469
1470    let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
1471    accounts.push(AccountMeta::new(*source_pubkey, false));
1472    accounts.push(AccountMeta::new_readonly(
1473        *owner_pubkey,
1474        signer_pubkeys.is_empty(),
1475    ));
1476    for signer_pubkey in signer_pubkeys.iter() {
1477        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1478    }
1479
1480    Ok(Instruction {
1481        program_id: *token_program_id,
1482        accounts,
1483        data,
1484    })
1485}
1486
1487/// Creates a `SetAuthority` instruction.
1488pub fn set_authority(
1489    token_program_id: &Pubkey,
1490    owned_pubkey: &Pubkey,
1491    new_authority_pubkey: Option<&Pubkey>,
1492    authority_type: AuthorityType,
1493    owner_pubkey: &Pubkey,
1494    signer_pubkeys: &[&Pubkey],
1495) -> Result<Instruction, ProgramError> {
1496    check_spl_token_program_account(token_program_id)?;
1497    let new_authority = new_authority_pubkey.cloned().into();
1498    let data = TokenInstruction::SetAuthority {
1499        authority_type,
1500        new_authority,
1501    }
1502    .pack();
1503
1504    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1505    accounts.push(AccountMeta::new(*owned_pubkey, false));
1506    accounts.push(AccountMeta::new_readonly(
1507        *owner_pubkey,
1508        signer_pubkeys.is_empty(),
1509    ));
1510    for signer_pubkey in signer_pubkeys.iter() {
1511        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1512    }
1513
1514    Ok(Instruction {
1515        program_id: *token_program_id,
1516        accounts,
1517        data,
1518    })
1519}
1520
1521/// Creates a `MintTo` instruction.
1522pub fn mint_to(
1523    token_program_id: &Pubkey,
1524    mint_pubkey: &Pubkey,
1525    account_pubkey: &Pubkey,
1526    owner_pubkey: &Pubkey,
1527    signer_pubkeys: &[&Pubkey],
1528    amount: u64,
1529) -> Result<Instruction, ProgramError> {
1530    check_spl_token_program_account(token_program_id)?;
1531    let data = TokenInstruction::MintTo { amount }.pack();
1532
1533    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1534    accounts.push(AccountMeta::new(*mint_pubkey, false));
1535    accounts.push(AccountMeta::new(*account_pubkey, false));
1536    accounts.push(AccountMeta::new_readonly(
1537        *owner_pubkey,
1538        signer_pubkeys.is_empty(),
1539    ));
1540    for signer_pubkey in signer_pubkeys.iter() {
1541        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1542    }
1543
1544    Ok(Instruction {
1545        program_id: *token_program_id,
1546        accounts,
1547        data,
1548    })
1549}
1550
1551/// Creates a `Burn` instruction.
1552pub fn burn(
1553    token_program_id: &Pubkey,
1554    account_pubkey: &Pubkey,
1555    mint_pubkey: &Pubkey,
1556    authority_pubkey: &Pubkey,
1557    signer_pubkeys: &[&Pubkey],
1558    amount: u64,
1559) -> Result<Instruction, ProgramError> {
1560    check_spl_token_program_account(token_program_id)?;
1561    let data = TokenInstruction::Burn { amount }.pack();
1562
1563    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1564    accounts.push(AccountMeta::new(*account_pubkey, false));
1565    accounts.push(AccountMeta::new(*mint_pubkey, false));
1566    accounts.push(AccountMeta::new_readonly(
1567        *authority_pubkey,
1568        signer_pubkeys.is_empty(),
1569    ));
1570    for signer_pubkey in signer_pubkeys.iter() {
1571        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1572    }
1573
1574    Ok(Instruction {
1575        program_id: *token_program_id,
1576        accounts,
1577        data,
1578    })
1579}
1580
1581/// Creates a `CloseAccount` instruction.
1582pub fn close_account(
1583    token_program_id: &Pubkey,
1584    account_pubkey: &Pubkey,
1585    destination_pubkey: &Pubkey,
1586    owner_pubkey: &Pubkey,
1587    signer_pubkeys: &[&Pubkey],
1588) -> Result<Instruction, ProgramError> {
1589    check_spl_token_program_account(token_program_id)?;
1590    let data = TokenInstruction::CloseAccount.pack();
1591
1592    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1593    accounts.push(AccountMeta::new(*account_pubkey, false));
1594    accounts.push(AccountMeta::new(*destination_pubkey, false));
1595    accounts.push(AccountMeta::new_readonly(
1596        *owner_pubkey,
1597        signer_pubkeys.is_empty(),
1598    ));
1599    for signer_pubkey in signer_pubkeys.iter() {
1600        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1601    }
1602
1603    Ok(Instruction {
1604        program_id: *token_program_id,
1605        accounts,
1606        data,
1607    })
1608}
1609
1610/// Creates a `FreezeAccount` instruction.
1611pub fn freeze_account(
1612    token_program_id: &Pubkey,
1613    account_pubkey: &Pubkey,
1614    mint_pubkey: &Pubkey,
1615    owner_pubkey: &Pubkey,
1616    signer_pubkeys: &[&Pubkey],
1617) -> Result<Instruction, ProgramError> {
1618    check_spl_token_program_account(token_program_id)?;
1619    let data = TokenInstruction::FreezeAccount.pack();
1620
1621    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1622    accounts.push(AccountMeta::new(*account_pubkey, false));
1623    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1624    accounts.push(AccountMeta::new_readonly(
1625        *owner_pubkey,
1626        signer_pubkeys.is_empty(),
1627    ));
1628    for signer_pubkey in signer_pubkeys.iter() {
1629        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1630    }
1631
1632    Ok(Instruction {
1633        program_id: *token_program_id,
1634        accounts,
1635        data,
1636    })
1637}
1638
1639/// Creates a `ThawAccount` instruction.
1640pub fn thaw_account(
1641    token_program_id: &Pubkey,
1642    account_pubkey: &Pubkey,
1643    mint_pubkey: &Pubkey,
1644    owner_pubkey: &Pubkey,
1645    signer_pubkeys: &[&Pubkey],
1646) -> Result<Instruction, ProgramError> {
1647    check_spl_token_program_account(token_program_id)?;
1648    let data = TokenInstruction::ThawAccount.pack();
1649
1650    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1651    accounts.push(AccountMeta::new(*account_pubkey, false));
1652    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1653    accounts.push(AccountMeta::new_readonly(
1654        *owner_pubkey,
1655        signer_pubkeys.is_empty(),
1656    ));
1657    for signer_pubkey in signer_pubkeys.iter() {
1658        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1659    }
1660
1661    Ok(Instruction {
1662        program_id: *token_program_id,
1663        accounts,
1664        data,
1665    })
1666}
1667
1668/// Creates a `TransferChecked` instruction.
1669#[allow(clippy::too_many_arguments)]
1670pub fn transfer_checked(
1671    token_program_id: &Pubkey,
1672    source_pubkey: &Pubkey,
1673    mint_pubkey: &Pubkey,
1674    destination_pubkey: &Pubkey,
1675    authority_pubkey: &Pubkey,
1676    signer_pubkeys: &[&Pubkey],
1677    amount: u64,
1678    decimals: u8,
1679) -> Result<Instruction, ProgramError> {
1680    check_spl_token_program_account(token_program_id)?;
1681    let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
1682
1683    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1684    accounts.push(AccountMeta::new(*source_pubkey, false));
1685    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1686    accounts.push(AccountMeta::new(*destination_pubkey, false));
1687    accounts.push(AccountMeta::new_readonly(
1688        *authority_pubkey,
1689        signer_pubkeys.is_empty(),
1690    ));
1691    for signer_pubkey in signer_pubkeys.iter() {
1692        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1693    }
1694
1695    Ok(Instruction {
1696        program_id: *token_program_id,
1697        accounts,
1698        data,
1699    })
1700}
1701
1702/// Creates an `ApproveChecked` instruction.
1703#[allow(clippy::too_many_arguments)]
1704pub fn approve_checked(
1705    token_program_id: &Pubkey,
1706    source_pubkey: &Pubkey,
1707    mint_pubkey: &Pubkey,
1708    delegate_pubkey: &Pubkey,
1709    owner_pubkey: &Pubkey,
1710    signer_pubkeys: &[&Pubkey],
1711    amount: u64,
1712    decimals: u8,
1713) -> Result<Instruction, ProgramError> {
1714    check_spl_token_program_account(token_program_id)?;
1715    let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
1716
1717    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1718    accounts.push(AccountMeta::new(*source_pubkey, false));
1719    accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
1720    accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
1721    accounts.push(AccountMeta::new_readonly(
1722        *owner_pubkey,
1723        signer_pubkeys.is_empty(),
1724    ));
1725    for signer_pubkey in signer_pubkeys.iter() {
1726        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1727    }
1728
1729    Ok(Instruction {
1730        program_id: *token_program_id,
1731        accounts,
1732        data,
1733    })
1734}
1735
1736/// Creates a `MintToChecked` instruction.
1737pub fn mint_to_checked(
1738    token_program_id: &Pubkey,
1739    mint_pubkey: &Pubkey,
1740    account_pubkey: &Pubkey,
1741    owner_pubkey: &Pubkey,
1742    signer_pubkeys: &[&Pubkey],
1743    amount: u64,
1744    decimals: u8,
1745) -> Result<Instruction, ProgramError> {
1746    check_spl_token_program_account(token_program_id)?;
1747    let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
1748
1749    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1750    accounts.push(AccountMeta::new(*mint_pubkey, false));
1751    accounts.push(AccountMeta::new(*account_pubkey, false));
1752    accounts.push(AccountMeta::new_readonly(
1753        *owner_pubkey,
1754        signer_pubkeys.is_empty(),
1755    ));
1756    for signer_pubkey in signer_pubkeys.iter() {
1757        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1758    }
1759
1760    Ok(Instruction {
1761        program_id: *token_program_id,
1762        accounts,
1763        data,
1764    })
1765}
1766
1767/// Creates a `BurnChecked` instruction.
1768pub fn burn_checked(
1769    token_program_id: &Pubkey,
1770    account_pubkey: &Pubkey,
1771    mint_pubkey: &Pubkey,
1772    authority_pubkey: &Pubkey,
1773    signer_pubkeys: &[&Pubkey],
1774    amount: u64,
1775    decimals: u8,
1776) -> Result<Instruction, ProgramError> {
1777    check_spl_token_program_account(token_program_id)?;
1778    let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
1779
1780    let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
1781    accounts.push(AccountMeta::new(*account_pubkey, false));
1782    accounts.push(AccountMeta::new(*mint_pubkey, false));
1783    accounts.push(AccountMeta::new_readonly(
1784        *authority_pubkey,
1785        signer_pubkeys.is_empty(),
1786    ));
1787    for signer_pubkey in signer_pubkeys.iter() {
1788        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1789    }
1790
1791    Ok(Instruction {
1792        program_id: *token_program_id,
1793        accounts,
1794        data,
1795    })
1796}
1797
1798/// Creates a `SyncNative` instruction
1799pub fn sync_native(
1800    token_program_id: &Pubkey,
1801    account_pubkey: &Pubkey,
1802) -> Result<Instruction, ProgramError> {
1803    check_spl_token_program_account(token_program_id)?;
1804
1805    Ok(Instruction {
1806        program_id: *token_program_id,
1807        accounts: vec![AccountMeta::new(*account_pubkey, false)],
1808        data: TokenInstruction::SyncNative.pack(),
1809    })
1810}
1811
1812/// Creates a `GetAccountDataSize` instruction
1813pub fn get_account_data_size(
1814    token_program_id: &Pubkey,
1815    mint_pubkey: &Pubkey,
1816    extension_types: &[ExtensionType],
1817) -> Result<Instruction, ProgramError> {
1818    check_spl_token_program_account(token_program_id)?;
1819    Ok(Instruction {
1820        program_id: *token_program_id,
1821        accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1822        data: TokenInstruction::GetAccountDataSize {
1823            extension_types: extension_types.to_vec(),
1824        }
1825        .pack(),
1826    })
1827}
1828
1829/// Creates an `InitializeMintCloseAuthority` instruction
1830pub fn initialize_mint_close_authority(
1831    token_program_id: &Pubkey,
1832    mint_pubkey: &Pubkey,
1833    close_authority: Option<&Pubkey>,
1834) -> Result<Instruction, ProgramError> {
1835    check_program_account(token_program_id)?;
1836    let close_authority = close_authority.cloned().into();
1837    Ok(Instruction {
1838        program_id: *token_program_id,
1839        accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1840        data: TokenInstruction::InitializeMintCloseAuthority { close_authority }.pack(),
1841    })
1842}
1843
1844/// Create an `InitializeImmutableOwner` instruction
1845pub fn initialize_immutable_owner(
1846    token_program_id: &Pubkey,
1847    token_account: &Pubkey,
1848) -> Result<Instruction, ProgramError> {
1849    check_spl_token_program_account(token_program_id)?;
1850    Ok(Instruction {
1851        program_id: *token_program_id,
1852        accounts: vec![AccountMeta::new(*token_account, false)],
1853        data: TokenInstruction::InitializeImmutableOwner.pack(),
1854    })
1855}
1856
1857/// Creates an `AmountToUiAmount` instruction
1858pub fn amount_to_ui_amount(
1859    token_program_id: &Pubkey,
1860    mint_pubkey: &Pubkey,
1861    amount: u64,
1862) -> Result<Instruction, ProgramError> {
1863    check_spl_token_program_account(token_program_id)?;
1864
1865    Ok(Instruction {
1866        program_id: *token_program_id,
1867        accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1868        data: TokenInstruction::AmountToUiAmount { amount }.pack(),
1869    })
1870}
1871
1872/// Creates a `UiAmountToAmount` instruction
1873pub fn ui_amount_to_amount(
1874    token_program_id: &Pubkey,
1875    mint_pubkey: &Pubkey,
1876    ui_amount: &str,
1877) -> Result<Instruction, ProgramError> {
1878    check_spl_token_program_account(token_program_id)?;
1879
1880    Ok(Instruction {
1881        program_id: *token_program_id,
1882        accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
1883        data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(),
1884    })
1885}
1886
1887/// Creates a `Reallocate` instruction
1888pub fn reallocate(
1889    token_program_id: &Pubkey,
1890    account_pubkey: &Pubkey,
1891    payer: &Pubkey,
1892    owner_pubkey: &Pubkey,
1893    signer_pubkeys: &[&Pubkey],
1894    extension_types: &[ExtensionType],
1895) -> Result<Instruction, ProgramError> {
1896    check_program_account(token_program_id)?;
1897
1898    let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
1899    accounts.push(AccountMeta::new(*account_pubkey, false));
1900    accounts.push(AccountMeta::new(*payer, true));
1901    accounts.push(AccountMeta::new_readonly(system_program::id(), false));
1902    accounts.push(AccountMeta::new_readonly(
1903        *owner_pubkey,
1904        signer_pubkeys.is_empty(),
1905    ));
1906    for signer_pubkey in signer_pubkeys.iter() {
1907        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
1908    }
1909
1910    Ok(Instruction {
1911        program_id: *token_program_id,
1912        accounts,
1913        data: TokenInstruction::Reallocate {
1914            extension_types: extension_types.to_vec(),
1915        }
1916        .pack(),
1917    })
1918}
1919
1920/// Creates a `CreateNativeMint` instruction
1921pub fn create_native_mint(
1922    token_program_id: &Pubkey,
1923    payer: &Pubkey,
1924) -> Result<Instruction, ProgramError> {
1925    check_program_account(token_program_id)?;
1926
1927    Ok(Instruction {
1928        program_id: *token_program_id,
1929        accounts: vec![
1930            AccountMeta::new(*payer, true),
1931            AccountMeta::new(crate::native_mint::id(), false),
1932            AccountMeta::new_readonly(system_program::id(), false),
1933        ],
1934        data: TokenInstruction::CreateNativeMint.pack(),
1935    })
1936}
1937
1938/// Creates an `InitializeNonTransferableMint` instruction
1939pub fn initialize_non_transferable_mint(
1940    token_program_id: &Pubkey,
1941    mint_pubkey: &Pubkey,
1942) -> Result<Instruction, ProgramError> {
1943    check_program_account(token_program_id)?;
1944    Ok(Instruction {
1945        program_id: *token_program_id,
1946        accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1947        data: TokenInstruction::InitializeNonTransferableMint.pack(),
1948    })
1949}
1950
1951/// Creates an `InitializePermanentDelegate` instruction
1952pub fn initialize_permanent_delegate(
1953    token_program_id: &Pubkey,
1954    mint_pubkey: &Pubkey,
1955    delegate: &Pubkey,
1956) -> Result<Instruction, ProgramError> {
1957    check_program_account(token_program_id)?;
1958    Ok(Instruction {
1959        program_id: *token_program_id,
1960        accounts: vec![AccountMeta::new(*mint_pubkey, false)],
1961        data: TokenInstruction::InitializePermanentDelegate {
1962            delegate: *delegate,
1963        }
1964        .pack(),
1965    })
1966}
1967
1968/// Utility function that checks index is between `MIN_SIGNERS` and
1969/// `MAX_SIGNERS`
1970pub fn is_valid_signer_index(index: usize) -> bool {
1971    (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
1972}
1973
1974/// Utility function for decoding just the instruction type
1975pub fn decode_instruction_type<T: TryFrom<u8>>(input: &[u8]) -> Result<T, ProgramError> {
1976    if input.is_empty() {
1977        Err(ProgramError::InvalidInstructionData)
1978    } else {
1979        T::try_from(input[0]).map_err(|_| TokenError::InvalidInstruction.into())
1980    }
1981}
1982
1983/// Utility function for decoding instruction data
1984///
1985/// Note: This function expects the entire instruction input, including the
1986/// instruction type as the first byte.  This makes the code concise and safe
1987/// at the expense of clarity, allowing flows such as:
1988///
1989/// ```
1990/// use spl_token_2022::instruction::{decode_instruction_data, decode_instruction_type};
1991/// use num_enum::TryFromPrimitive;
1992/// use bytemuck::{Pod, Zeroable};
1993///
1994/// #[repr(u8)]
1995/// #[derive(Clone, Copy, TryFromPrimitive)]
1996/// enum InstructionType {
1997///     First
1998/// }
1999/// #[derive(Pod, Zeroable, Copy, Clone)]
2000/// #[repr(transparent)]
2001/// struct FirstData {
2002///     a: u8,
2003/// }
2004/// let input = [0, 1];
2005/// match decode_instruction_type(&input).unwrap() {
2006///     InstructionType::First => {
2007///         let FirstData { a } = decode_instruction_data(&input).unwrap();
2008///         assert_eq!(*a, 1);
2009///     }
2010/// }
2011/// ```
2012pub fn decode_instruction_data<T: Pod>(input_with_type: &[u8]) -> Result<&T, ProgramError> {
2013    if input_with_type.len() != pod_get_packed_len::<T>().saturating_add(1) {
2014        Err(ProgramError::InvalidInstructionData)
2015    } else {
2016        pod_from_bytes(&input_with_type[1..])
2017    }
2018}
2019
2020/// Utility function for encoding instruction data
2021pub(crate) fn encode_instruction<T: Into<u8>, D: Pod>(
2022    token_program_id: &Pubkey,
2023    accounts: Vec<AccountMeta>,
2024    token_instruction_type: TokenInstruction,
2025    instruction_type: T,
2026    instruction_data: &D,
2027) -> Instruction {
2028    let mut data = token_instruction_type.pack();
2029    data.push(T::into(instruction_type));
2030    data.extend_from_slice(bytemuck::bytes_of(instruction_data));
2031    Instruction {
2032        program_id: *token_program_id,
2033        accounts,
2034        data,
2035    }
2036}
2037
2038/// Creates a `WithdrawExcessLamports` Instruction
2039pub fn withdraw_excess_lamports(
2040    token_program_id: &Pubkey,
2041    source_account: &Pubkey,
2042    destination_account: &Pubkey,
2043    authority: &Pubkey,
2044    signers: &[&Pubkey],
2045) -> Result<Instruction, ProgramError> {
2046    check_program_account(token_program_id)?;
2047
2048    let mut accounts = vec![
2049        AccountMeta::new(*source_account, false),
2050        AccountMeta::new(*destination_account, false),
2051        AccountMeta::new_readonly(*authority, signers.is_empty()),
2052    ];
2053
2054    for signer in signers {
2055        accounts.push(AccountMeta::new_readonly(**signer, true))
2056    }
2057
2058    Ok(Instruction {
2059        program_id: *token_program_id,
2060        accounts,
2061        data: TokenInstruction::WithdrawExcessLamports.pack(),
2062    })
2063}
2064
2065#[cfg(test)]
2066mod test {
2067    use {super::*, crate::pod_instruction::*, proptest::prelude::*};
2068
2069    #[test]
2070    fn test_initialize_mint_packing() {
2071        let decimals = 2;
2072        let mint_authority = Pubkey::new_from_array([1u8; 32]);
2073        let freeze_authority = COption::None;
2074        let check = TokenInstruction::InitializeMint {
2075            decimals,
2076            mint_authority,
2077            freeze_authority,
2078        };
2079        let packed = check.pack();
2080        let mut expect = Vec::from([0u8, 2]);
2081        expect.extend_from_slice(&[1u8; 32]);
2082        expect.extend_from_slice(&[0]);
2083        assert_eq!(packed, expect);
2084        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2085        assert_eq!(unpacked, check);
2086        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2087        assert_eq!(instruction_type, PodTokenInstruction::InitializeMint);
2088        let (pod, pod_freeze_authority) =
2089            decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2090        assert_eq!(pod.decimals, decimals);
2091        assert_eq!(pod.mint_authority, mint_authority);
2092        assert_eq!(pod_freeze_authority, freeze_authority.into());
2093
2094        let mint_authority = Pubkey::new_from_array([2u8; 32]);
2095        let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2096        let check = TokenInstruction::InitializeMint {
2097            decimals,
2098            mint_authority,
2099            freeze_authority,
2100        };
2101        let packed = check.pack();
2102        let mut expect = vec![0u8, 2];
2103        expect.extend_from_slice(&[2u8; 32]);
2104        expect.extend_from_slice(&[1]);
2105        expect.extend_from_slice(&[3u8; 32]);
2106        assert_eq!(packed, expect);
2107        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2108        assert_eq!(unpacked, check);
2109
2110        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2111        assert_eq!(instruction_type, PodTokenInstruction::InitializeMint);
2112        let (pod, pod_freeze_authority) =
2113            decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2114        assert_eq!(pod.decimals, decimals);
2115        assert_eq!(pod.mint_authority, mint_authority);
2116        assert_eq!(pod_freeze_authority, freeze_authority.into());
2117    }
2118
2119    #[test]
2120    fn test_initialize_account_packing() {
2121        let check = TokenInstruction::InitializeAccount;
2122        let packed = check.pack();
2123        let expect = Vec::from([1u8]);
2124        assert_eq!(packed, expect);
2125        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2126        assert_eq!(unpacked, check);
2127        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2128        assert_eq!(instruction_type, PodTokenInstruction::InitializeAccount);
2129    }
2130
2131    #[test]
2132    fn test_initialize_multisig_packing() {
2133        let m = 1;
2134        let check = TokenInstruction::InitializeMultisig { m };
2135        let packed = check.pack();
2136        let expect = Vec::from([2u8, 1]);
2137        assert_eq!(packed, expect);
2138        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2139        assert_eq!(unpacked, check);
2140
2141        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2142        assert_eq!(instruction_type, PodTokenInstruction::InitializeMultisig);
2143        let pod = decode_instruction_data::<InitializeMultisigData>(&packed).unwrap();
2144        assert_eq!(pod.m, m);
2145    }
2146
2147    #[test]
2148    fn test_transfer_packing() {
2149        let amount = 1;
2150        #[allow(deprecated)]
2151        let check = TokenInstruction::Transfer { amount };
2152        let packed = check.pack();
2153        let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2154        assert_eq!(packed, expect);
2155        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2156        assert_eq!(unpacked, check);
2157
2158        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2159        assert_eq!(instruction_type, PodTokenInstruction::Transfer);
2160        let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2161        assert_eq!(pod.amount, amount.into());
2162    }
2163
2164    #[test]
2165    fn test_approve_packing() {
2166        let amount = 1;
2167        let check = TokenInstruction::Approve { amount };
2168        let packed = check.pack();
2169        let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2170        assert_eq!(packed, expect);
2171        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2172        assert_eq!(unpacked, check);
2173
2174        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2175        assert_eq!(instruction_type, PodTokenInstruction::Approve);
2176        let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2177        assert_eq!(pod.amount, amount.into());
2178    }
2179
2180    #[test]
2181    fn test_revoke_packing() {
2182        let check = TokenInstruction::Revoke;
2183        let packed = check.pack();
2184        let expect = Vec::from([5u8]);
2185        assert_eq!(packed, expect);
2186        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2187        assert_eq!(unpacked, check);
2188        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2189        assert_eq!(instruction_type, PodTokenInstruction::Revoke);
2190    }
2191
2192    #[test]
2193    fn test_set_authority_packing() {
2194        let authority_type = AuthorityType::FreezeAccount;
2195        let new_authority = COption::Some(Pubkey::new_from_array([4u8; 32]));
2196        let check = TokenInstruction::SetAuthority {
2197            authority_type: authority_type.clone(),
2198            new_authority,
2199        };
2200        let packed = check.pack();
2201        let mut expect = Vec::from([6u8, 1]);
2202        expect.extend_from_slice(&[1]);
2203        expect.extend_from_slice(&[4u8; 32]);
2204        assert_eq!(packed, expect);
2205        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2206        assert_eq!(unpacked, check);
2207
2208        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2209        assert_eq!(instruction_type, PodTokenInstruction::SetAuthority);
2210        let (pod, pod_new_authority) =
2211            decode_instruction_data_with_coption_pubkey::<SetAuthorityData>(&packed).unwrap();
2212        assert_eq!(
2213            AuthorityType::from(pod.authority_type).unwrap(),
2214            authority_type
2215        );
2216        assert_eq!(pod_new_authority, new_authority.into());
2217    }
2218
2219    #[test]
2220    fn test_mint_to_packing() {
2221        let amount = 1;
2222        let check = TokenInstruction::MintTo { amount };
2223        let packed = check.pack();
2224        let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2225        assert_eq!(packed, expect);
2226        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2227        assert_eq!(unpacked, check);
2228
2229        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2230        assert_eq!(instruction_type, PodTokenInstruction::MintTo);
2231        let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2232        assert_eq!(pod.amount, amount.into());
2233    }
2234
2235    #[test]
2236    fn test_burn_packing() {
2237        let amount = 1;
2238        let check = TokenInstruction::Burn { amount };
2239        let packed = check.pack();
2240        let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
2241        assert_eq!(packed, expect);
2242        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2243        assert_eq!(unpacked, check);
2244
2245        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2246        assert_eq!(instruction_type, PodTokenInstruction::Burn);
2247        let pod = decode_instruction_data::<AmountData>(&packed).unwrap();
2248        assert_eq!(pod.amount, amount.into());
2249    }
2250
2251    #[test]
2252    fn test_close_account_packing() {
2253        let check = TokenInstruction::CloseAccount;
2254        let packed = check.pack();
2255        let expect = Vec::from([9u8]);
2256        assert_eq!(packed, expect);
2257        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2258        assert_eq!(unpacked, check);
2259        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2260        assert_eq!(instruction_type, PodTokenInstruction::CloseAccount);
2261    }
2262
2263    #[test]
2264    fn test_freeze_account_packing() {
2265        let check = TokenInstruction::FreezeAccount;
2266        let packed = check.pack();
2267        let expect = Vec::from([10u8]);
2268        assert_eq!(packed, expect);
2269        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2270        assert_eq!(unpacked, check);
2271        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2272        assert_eq!(instruction_type, PodTokenInstruction::FreezeAccount);
2273    }
2274
2275    #[test]
2276    fn test_thaw_account_packing() {
2277        let check = TokenInstruction::ThawAccount;
2278        let packed = check.pack();
2279        let expect = Vec::from([11u8]);
2280        assert_eq!(packed, expect);
2281        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2282        assert_eq!(unpacked, check);
2283        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2284        assert_eq!(instruction_type, PodTokenInstruction::ThawAccount);
2285    }
2286
2287    #[test]
2288    fn test_transfer_checked_packing() {
2289        let amount = 1;
2290        let decimals = 2;
2291        let check = TokenInstruction::TransferChecked { amount, decimals };
2292        let packed = check.pack();
2293        let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2294        assert_eq!(packed, expect);
2295        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2296        assert_eq!(unpacked, check);
2297
2298        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2299        assert_eq!(instruction_type, PodTokenInstruction::TransferChecked);
2300        let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2301        assert_eq!(pod.amount, amount.into());
2302        assert_eq!(pod.decimals, decimals);
2303    }
2304
2305    #[test]
2306    fn test_approve_checked_packing() {
2307        let amount = 1;
2308        let decimals = 2;
2309
2310        let check = TokenInstruction::ApproveChecked { amount, decimals };
2311        let packed = check.pack();
2312        let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2313        assert_eq!(packed, expect);
2314        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2315        assert_eq!(unpacked, check);
2316
2317        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2318        assert_eq!(instruction_type, PodTokenInstruction::ApproveChecked);
2319        let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2320        assert_eq!(pod.amount, amount.into());
2321        assert_eq!(pod.decimals, decimals);
2322    }
2323
2324    #[test]
2325    fn test_mint_to_checked_packing() {
2326        let amount = 1;
2327        let decimals = 2;
2328        let check = TokenInstruction::MintToChecked { amount, decimals };
2329        let packed = check.pack();
2330        let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2331        assert_eq!(packed, expect);
2332        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2333        assert_eq!(unpacked, check);
2334        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2335        assert_eq!(instruction_type, PodTokenInstruction::MintToChecked);
2336        let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2337        assert_eq!(pod.amount, amount.into());
2338        assert_eq!(pod.decimals, decimals);
2339    }
2340
2341    #[test]
2342    fn test_burn_checked_packing() {
2343        let amount = 1;
2344        let decimals = 2;
2345        let check = TokenInstruction::BurnChecked { amount, decimals };
2346        let packed = check.pack();
2347        let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
2348        assert_eq!(packed, expect);
2349        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2350        assert_eq!(unpacked, check);
2351
2352        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2353        assert_eq!(instruction_type, PodTokenInstruction::BurnChecked);
2354        let pod = decode_instruction_data::<AmountCheckedData>(&packed).unwrap();
2355        assert_eq!(pod.amount, amount.into());
2356        assert_eq!(pod.decimals, decimals);
2357    }
2358
2359    #[test]
2360    fn test_initialize_account2_packing() {
2361        let owner = Pubkey::new_from_array([2u8; 32]);
2362        let check = TokenInstruction::InitializeAccount2 { owner };
2363        let packed = check.pack();
2364        let mut expect = vec![16u8];
2365        expect.extend_from_slice(&[2u8; 32]);
2366        assert_eq!(packed, expect);
2367        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2368        assert_eq!(unpacked, check);
2369
2370        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2371        assert_eq!(instruction_type, PodTokenInstruction::InitializeAccount2);
2372        let pod_owner = decode_instruction_data::<Pubkey>(&packed).unwrap();
2373        assert_eq!(*pod_owner, owner);
2374    }
2375
2376    #[test]
2377    fn test_sync_native_packing() {
2378        let check = TokenInstruction::SyncNative;
2379        let packed = check.pack();
2380        let expect = vec![17u8];
2381        assert_eq!(packed, expect);
2382        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2383        assert_eq!(unpacked, check);
2384
2385        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2386        assert_eq!(instruction_type, PodTokenInstruction::SyncNative);
2387    }
2388
2389    #[test]
2390    fn test_initialize_account3_packing() {
2391        let owner = Pubkey::new_from_array([2u8; 32]);
2392        let check = TokenInstruction::InitializeAccount3 { owner };
2393        let packed = check.pack();
2394        let mut expect = vec![18u8];
2395        expect.extend_from_slice(&[2u8; 32]);
2396        assert_eq!(packed, expect);
2397        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2398        assert_eq!(unpacked, check);
2399
2400        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2401        assert_eq!(instruction_type, PodTokenInstruction::InitializeAccount3);
2402        let pod_owner = decode_instruction_data::<Pubkey>(&packed).unwrap();
2403        assert_eq!(*pod_owner, owner);
2404    }
2405
2406    #[test]
2407    fn test_initialize_multisig2_packing() {
2408        let m = 1;
2409        let check = TokenInstruction::InitializeMultisig2 { m };
2410        let packed = check.pack();
2411        let expect = Vec::from([19u8, 1]);
2412        assert_eq!(packed, expect);
2413        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2414        assert_eq!(unpacked, check);
2415
2416        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2417        assert_eq!(instruction_type, PodTokenInstruction::InitializeMultisig2);
2418        let pod = decode_instruction_data::<InitializeMultisigData>(&packed).unwrap();
2419        assert_eq!(pod.m, m);
2420    }
2421
2422    #[test]
2423    fn test_initialize_mint2_packing() {
2424        let decimals = 2;
2425        let mint_authority = Pubkey::new_from_array([1u8; 32]);
2426        let freeze_authority = COption::None;
2427        let check = TokenInstruction::InitializeMint2 {
2428            decimals,
2429            mint_authority,
2430            freeze_authority,
2431        };
2432        let packed = check.pack();
2433        let mut expect = Vec::from([20u8, 2]);
2434        expect.extend_from_slice(&[1u8; 32]);
2435        expect.extend_from_slice(&[0]);
2436        assert_eq!(packed, expect);
2437        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2438        assert_eq!(unpacked, check);
2439
2440        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2441        assert_eq!(instruction_type, PodTokenInstruction::InitializeMint2);
2442        let (pod, pod_freeze_authority) =
2443            decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2444        assert_eq!(pod.decimals, decimals);
2445        assert_eq!(pod.mint_authority, mint_authority);
2446        assert_eq!(pod_freeze_authority, freeze_authority.into());
2447
2448        let decimals = 2;
2449        let mint_authority = Pubkey::new_from_array([2u8; 32]);
2450        let freeze_authority = COption::Some(Pubkey::new_from_array([3u8; 32]));
2451        let check = TokenInstruction::InitializeMint2 {
2452            decimals,
2453            mint_authority,
2454            freeze_authority,
2455        };
2456        let packed = check.pack();
2457        let mut expect = vec![20u8, 2];
2458        expect.extend_from_slice(&[2u8; 32]);
2459        expect.extend_from_slice(&[1]);
2460        expect.extend_from_slice(&[3u8; 32]);
2461        assert_eq!(packed, expect);
2462        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2463        assert_eq!(unpacked, check);
2464
2465        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2466        assert_eq!(instruction_type, PodTokenInstruction::InitializeMint2);
2467        let (pod, pod_freeze_authority) =
2468            decode_instruction_data_with_coption_pubkey::<InitializeMintData>(&packed).unwrap();
2469        assert_eq!(pod.decimals, decimals);
2470        assert_eq!(pod.mint_authority, mint_authority);
2471        assert_eq!(pod_freeze_authority, freeze_authority.into());
2472    }
2473
2474    #[test]
2475    fn test_get_account_data_size_packing() {
2476        let extension_types = vec![];
2477        let check = TokenInstruction::GetAccountDataSize {
2478            extension_types: extension_types.clone(),
2479        };
2480        let packed = check.pack();
2481        let expect = [21u8];
2482        assert_eq!(packed, &[21u8]);
2483        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2484        assert_eq!(unpacked, check);
2485
2486        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2487        assert_eq!(instruction_type, PodTokenInstruction::GetAccountDataSize);
2488        let pod_extension_types = packed[1..]
2489            .chunks(std::mem::size_of::<ExtensionType>())
2490            .map(ExtensionType::try_from)
2491            .collect::<Result<Vec<_>, _>>()
2492            .unwrap();
2493        assert_eq!(pod_extension_types, extension_types);
2494
2495        let extension_types = vec![
2496            ExtensionType::TransferFeeConfig,
2497            ExtensionType::TransferFeeAmount,
2498        ];
2499        let check = TokenInstruction::GetAccountDataSize {
2500            extension_types: extension_types.clone(),
2501        };
2502        let packed = check.pack();
2503        let expect = [21u8, 1, 0, 2, 0];
2504        assert_eq!(packed, &[21u8, 1, 0, 2, 0]);
2505        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2506        assert_eq!(unpacked, check);
2507
2508        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2509        assert_eq!(instruction_type, PodTokenInstruction::GetAccountDataSize);
2510        let pod_extension_types = packed[1..]
2511            .chunks(std::mem::size_of::<ExtensionType>())
2512            .map(ExtensionType::try_from)
2513            .collect::<Result<Vec<_>, _>>()
2514            .unwrap();
2515        assert_eq!(pod_extension_types, extension_types);
2516    }
2517
2518    #[test]
2519    fn test_amount_to_ui_amount_packing() {
2520        let amount = 42;
2521        let check = TokenInstruction::AmountToUiAmount { amount };
2522        let packed = check.pack();
2523        let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0];
2524        assert_eq!(packed, expect);
2525        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2526        assert_eq!(unpacked, check);
2527
2528        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2529        assert_eq!(instruction_type, PodTokenInstruction::AmountToUiAmount);
2530        let data = decode_instruction_data::<AmountData>(&packed).unwrap();
2531        assert_eq!(data.amount, amount.into());
2532    }
2533
2534    #[test]
2535    fn test_ui_amount_to_amount_packing() {
2536        let ui_amount = "0.42";
2537        let check = TokenInstruction::UiAmountToAmount { ui_amount };
2538        let packed = check.pack();
2539        let expect = vec![24u8, 48, 46, 52, 50];
2540        assert_eq!(packed, expect);
2541        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2542        assert_eq!(unpacked, check);
2543
2544        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2545        assert_eq!(instruction_type, PodTokenInstruction::UiAmountToAmount);
2546        let pod_ui_amount = std::str::from_utf8(&packed[1..]).unwrap();
2547        assert_eq!(pod_ui_amount, ui_amount);
2548    }
2549
2550    #[test]
2551    fn test_initialize_mint_close_authority_packing() {
2552        let close_authority = COption::Some(Pubkey::new_from_array([10u8; 32]));
2553        let check = TokenInstruction::InitializeMintCloseAuthority { close_authority };
2554        let packed = check.pack();
2555        let mut expect = vec![25u8, 1];
2556        expect.extend_from_slice(&[10u8; 32]);
2557        assert_eq!(packed, expect);
2558        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2559        assert_eq!(unpacked, check);
2560
2561        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2562        assert_eq!(
2563            instruction_type,
2564            PodTokenInstruction::InitializeMintCloseAuthority
2565        );
2566        let (_, pod_close_authority) =
2567            decode_instruction_data_with_coption_pubkey::<()>(&packed).unwrap();
2568        assert_eq!(pod_close_authority, close_authority.into());
2569    }
2570
2571    #[test]
2572    fn test_create_native_mint_packing() {
2573        let check = TokenInstruction::CreateNativeMint;
2574        let packed = check.pack();
2575        let expect = vec![31u8];
2576        assert_eq!(packed, expect);
2577        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2578        assert_eq!(unpacked, check);
2579
2580        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2581        assert_eq!(instruction_type, PodTokenInstruction::CreateNativeMint);
2582    }
2583
2584    #[test]
2585    fn test_initialize_permanent_delegate_packing() {
2586        let delegate = Pubkey::new_from_array([11u8; 32]);
2587        let check = TokenInstruction::InitializePermanentDelegate { delegate };
2588        let packed = check.pack();
2589        let mut expect = vec![35u8];
2590        expect.extend_from_slice(&[11u8; 32]);
2591        assert_eq!(packed, expect);
2592        let unpacked = TokenInstruction::unpack(&expect).unwrap();
2593        assert_eq!(unpacked, check);
2594
2595        let instruction_type = decode_instruction_type::<PodTokenInstruction>(&packed).unwrap();
2596        assert_eq!(
2597            instruction_type,
2598            PodTokenInstruction::InitializePermanentDelegate
2599        );
2600        let pod_delegate = decode_instruction_data::<Pubkey>(&packed).unwrap();
2601        assert_eq!(*pod_delegate, delegate);
2602    }
2603
2604    macro_rules! test_instruction {
2605        ($a:ident($($b:tt)*)) => {
2606            let instruction_v3 = spl_token::instruction::$a($($b)*).unwrap();
2607            let instruction_2022 = $a($($b)*).unwrap();
2608            assert_eq!(instruction_v3, instruction_2022);
2609        }
2610    }
2611
2612    #[test]
2613    fn test_v3_compatibility() {
2614        let token_program_id = spl_token::id();
2615        let mint_pubkey = Pubkey::new_unique();
2616        let mint_authority_pubkey = Pubkey::new_unique();
2617        let freeze_authority_pubkey = Pubkey::new_unique();
2618        let decimals = 9u8;
2619
2620        let account_pubkey = Pubkey::new_unique();
2621        let owner_pubkey = Pubkey::new_unique();
2622
2623        let multisig_pubkey = Pubkey::new_unique();
2624        let signer_pubkeys_vec = vec![Pubkey::new_unique(); MAX_SIGNERS];
2625        let signer_pubkeys = signer_pubkeys_vec.iter().collect::<Vec<_>>();
2626        let m = 10u8;
2627
2628        let source_pubkey = Pubkey::new_unique();
2629        let destination_pubkey = Pubkey::new_unique();
2630        let authority_pubkey = Pubkey::new_unique();
2631        let amount = 1_000_000_000_000;
2632
2633        let delegate_pubkey = Pubkey::new_unique();
2634        let owned_pubkey = Pubkey::new_unique();
2635        let new_authority_pubkey = Pubkey::new_unique();
2636
2637        let ui_amount = "100000.00";
2638
2639        test_instruction!(initialize_mint(
2640            &token_program_id,
2641            &mint_pubkey,
2642            &mint_authority_pubkey,
2643            None,
2644            decimals,
2645        ));
2646        test_instruction!(initialize_mint2(
2647            &token_program_id,
2648            &mint_pubkey,
2649            &mint_authority_pubkey,
2650            Some(&freeze_authority_pubkey),
2651            decimals,
2652        ));
2653
2654        test_instruction!(initialize_account(
2655            &token_program_id,
2656            &account_pubkey,
2657            &mint_pubkey,
2658            &owner_pubkey,
2659        ));
2660        test_instruction!(initialize_account2(
2661            &token_program_id,
2662            &account_pubkey,
2663            &mint_pubkey,
2664            &owner_pubkey,
2665        ));
2666        test_instruction!(initialize_account3(
2667            &token_program_id,
2668            &account_pubkey,
2669            &mint_pubkey,
2670            &owner_pubkey,
2671        ));
2672        test_instruction!(initialize_multisig(
2673            &token_program_id,
2674            &multisig_pubkey,
2675            &signer_pubkeys,
2676            m,
2677        ));
2678        test_instruction!(initialize_multisig2(
2679            &token_program_id,
2680            &multisig_pubkey,
2681            &signer_pubkeys,
2682            m,
2683        ));
2684        #[allow(deprecated)]
2685        {
2686            test_instruction!(transfer(
2687                &token_program_id,
2688                &source_pubkey,
2689                &destination_pubkey,
2690                &authority_pubkey,
2691                &signer_pubkeys,
2692                amount
2693            ));
2694        }
2695        test_instruction!(transfer_checked(
2696            &token_program_id,
2697            &source_pubkey,
2698            &mint_pubkey,
2699            &destination_pubkey,
2700            &authority_pubkey,
2701            &signer_pubkeys,
2702            amount,
2703            decimals,
2704        ));
2705        test_instruction!(approve(
2706            &token_program_id,
2707            &source_pubkey,
2708            &delegate_pubkey,
2709            &owner_pubkey,
2710            &signer_pubkeys,
2711            amount
2712        ));
2713        test_instruction!(approve_checked(
2714            &token_program_id,
2715            &source_pubkey,
2716            &mint_pubkey,
2717            &delegate_pubkey,
2718            &owner_pubkey,
2719            &signer_pubkeys,
2720            amount,
2721            decimals
2722        ));
2723        test_instruction!(revoke(
2724            &token_program_id,
2725            &source_pubkey,
2726            &owner_pubkey,
2727            &signer_pubkeys,
2728        ));
2729
2730        // set_authority
2731        {
2732            let instruction_v3 = spl_token::instruction::set_authority(
2733                &token_program_id,
2734                &owned_pubkey,
2735                Some(&new_authority_pubkey),
2736                spl_token::instruction::AuthorityType::AccountOwner,
2737                &owner_pubkey,
2738                &signer_pubkeys,
2739            )
2740            .unwrap();
2741            let instruction_2022 = set_authority(
2742                &token_program_id,
2743                &owned_pubkey,
2744                Some(&new_authority_pubkey),
2745                AuthorityType::AccountOwner,
2746                &owner_pubkey,
2747                &signer_pubkeys,
2748            )
2749            .unwrap();
2750            assert_eq!(instruction_v3, instruction_2022);
2751        }
2752
2753        test_instruction!(mint_to(
2754            &token_program_id,
2755            &mint_pubkey,
2756            &account_pubkey,
2757            &owner_pubkey,
2758            &signer_pubkeys,
2759            amount,
2760        ));
2761        test_instruction!(mint_to_checked(
2762            &token_program_id,
2763            &mint_pubkey,
2764            &account_pubkey,
2765            &owner_pubkey,
2766            &signer_pubkeys,
2767            amount,
2768            decimals,
2769        ));
2770        test_instruction!(burn(
2771            &token_program_id,
2772            &account_pubkey,
2773            &mint_pubkey,
2774            &authority_pubkey,
2775            &signer_pubkeys,
2776            amount,
2777        ));
2778        test_instruction!(burn_checked(
2779            &token_program_id,
2780            &account_pubkey,
2781            &mint_pubkey,
2782            &authority_pubkey,
2783            &signer_pubkeys,
2784            amount,
2785            decimals,
2786        ));
2787        test_instruction!(close_account(
2788            &token_program_id,
2789            &account_pubkey,
2790            &destination_pubkey,
2791            &owner_pubkey,
2792            &signer_pubkeys,
2793        ));
2794        test_instruction!(freeze_account(
2795            &token_program_id,
2796            &account_pubkey,
2797            &mint_pubkey,
2798            &owner_pubkey,
2799            &signer_pubkeys,
2800        ));
2801        test_instruction!(thaw_account(
2802            &token_program_id,
2803            &account_pubkey,
2804            &mint_pubkey,
2805            &owner_pubkey,
2806            &signer_pubkeys,
2807        ));
2808        test_instruction!(sync_native(&token_program_id, &account_pubkey,));
2809
2810        // get_account_data_size
2811        {
2812            let instruction_v3 =
2813                spl_token::instruction::get_account_data_size(&token_program_id, &mint_pubkey)
2814                    .unwrap();
2815            let instruction_2022 =
2816                get_account_data_size(&token_program_id, &mint_pubkey, &[]).unwrap();
2817            assert_eq!(instruction_v3, instruction_2022);
2818        }
2819
2820        test_instruction!(initialize_immutable_owner(
2821            &token_program_id,
2822            &account_pubkey,
2823        ));
2824
2825        test_instruction!(amount_to_ui_amount(&token_program_id, &mint_pubkey, amount,));
2826
2827        test_instruction!(ui_amount_to_amount(
2828            &token_program_id,
2829            &mint_pubkey,
2830            ui_amount,
2831        ));
2832    }
2833
2834    proptest! {
2835        #![proptest_config(ProptestConfig::with_cases(1024))]
2836        #[test]
2837        fn test_instruction_unpack_proptest(
2838            data in prop::collection::vec(any::<u8>(), 0..255)
2839        ) {
2840            let _no_panic = TokenInstruction::unpack(&data);
2841        }
2842    }
2843}