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