Skip to main content

spl_token_2022_interface/
instruction.rs

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