safe_token_2022/
instruction.rs

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