substreams_solana_program_instructions/
token_instruction_2022.rs

1//! Instruction types
2
3#![allow(deprecated)] // needed to avoid deprecation warning when generating serde implementation for TokenInstruction
4
5use anyhow::anyhow;
6use {
7    substreams::{errors::Error},
8    num_enum::{IntoPrimitive, TryFromPrimitive},
9    crate::{transfer_fee_instruction::TransferFeeInstruction},
10    std::{
11        convert::{TryFrom, TryInto},
12        mem::size_of,
13    },
14};
15
16#[cfg(feature = "serde-traits")]
17use {
18    crate::serialization::coption_fromstr,
19    serde::{Deserialize, Serialize},
20    serde_with::{As, DisplayFromStr},
21};
22use crate::option::COption;
23use crate::pubkey::{Pubkey, PUBKEY_BYTES};
24
25/// Minimum number of multisignature signers (min N)
26pub const MIN_SIGNERS: usize = 1;
27/// Maximum number of multisignature signers (max N)
28pub const MAX_SIGNERS: usize = 11;
29/// Serialized length of a u16, for unpacking
30const U16_BYTES: usize = 2;
31/// Serialized length of a u64, for unpacking
32const U64_BYTES: usize = 8;
33
34/// Instructions supported by the token program.
35#[repr(C)]
36#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
37#[cfg_attr(
38    feature = "serde-traits",
39    serde(rename_all_fields = "camelCase", rename_all = "camelCase")
40)]
41#[derive(Clone, Debug, PartialEq)]
42pub enum TokenInstruction<'a> {
43    /// Initializes a new mint and optionally deposits all the newly minted
44    /// tokens in an account.
45    ///
46    /// The `InitializeMint` instruction requires no signers and MUST be
47    /// included within the same Transaction as the system program's
48    /// `CreateAccount` instruction that creates the account being initialized.
49    /// Otherwise another party can acquire ownership of the uninitialized
50    /// account.
51    ///
52    /// All extensions must be initialized before calling this instruction.
53    ///
54    /// Accounts expected by this instruction:
55    ///
56    ///   0. `[writable]` The mint to initialize.
57    ///   1. `[]` Rent sysvar
58    ///
59    InitializeMint {
60        /// Number of base 10 digits to the right of the decimal place.
61        decimals: u8,
62        /// The authority/multisignature to mint tokens.
63        #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
64        mint_authority: Pubkey,
65        /// The freeze authority/multisignature of the mint.
66        #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
67        freeze_authority: COption<Pubkey>,
68    },
69    /// Initializes a new account to hold tokens.  If this account is associated
70    /// with the native mint then the token balance of the initialized account
71    /// will be equal to the amount of SOL in the account. If this account is
72    /// associated with another mint, that mint must be initialized before this
73    /// command can succeed.
74    ///
75    /// The `InitializeAccount` instruction requires no signers and MUST be
76    /// included within the same Transaction as the system program's
77    /// `CreateAccount` instruction that creates the account being initialized.
78    /// Otherwise another party can acquire ownership of the uninitialized
79    /// account.
80    ///
81    /// Accounts expected by this instruction:
82    ///
83    ///   0. `[writable]`  The account to initialize.
84    ///   1. `[]` The mint this account will be associated with.
85    ///   2. `[]` The new account's owner/multisignature.
86    ///   3. `[]` Rent sysvar
87    InitializeAccount,
88    /// Initializes a multisignature account with N provided signers.
89    ///
90    /// Multisignature accounts can used in place of any single owner/delegate
91    /// accounts in any token instruction that require an owner/delegate to be
92    /// present.  The variant field represents the number of signers (M)
93    /// required to validate this multisignature account.
94    ///
95    /// The `InitializeMultisig` instruction requires no signers and MUST be
96    /// included within the same Transaction as the system program's
97    /// `CreateAccount` instruction that creates the account being initialized.
98    /// Otherwise another party can acquire ownership of the uninitialized
99    /// account.
100    ///
101    /// Accounts expected by this instruction:
102    ///
103    ///   0. `[writable]` The multisignature account to initialize.
104    ///   1. `[]` Rent sysvar
105    ///   2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <=
106    ///      11.
107    InitializeMultisig {
108        /// The number of signers (M) required to validate this multisignature
109        /// account.
110        m: u8,
111    },
112    /// NOTE This instruction is deprecated in favor of `TransferChecked` or
113    /// `TransferCheckedWithFee`
114    ///
115    /// Transfers tokens from one account to another either directly or via a
116    /// delegate.  If this account is associated with the native mint then equal
117    /// amounts of SOL and Tokens will be transferred to the destination
118    /// account.
119    ///
120    /// If either account contains an `TransferFeeAmount` extension, this will fail.
121    /// Mints with the `TransferFeeConfig` extension are required in order to assess the fee.
122    ///
123    /// Accounts expected by this instruction:
124    ///
125    ///   * Single owner/delegate
126    ///   0. `[writable]` The source account.
127    ///   1. `[writable]` The destination account.
128    ///   2. `[signer]` The source account's owner/delegate.
129    ///
130    ///   * Multisignature owner/delegate
131    ///   0. `[writable]` The source account.
132    ///   1. `[writable]` The destination account.
133    ///   2. `[]` The source account's multisignature owner/delegate.
134    ///   3. ..3+M `[signer]` M signer accounts.
135    #[deprecated(
136        since = "4.0.0",
137        note = "please use `TransferChecked` or `TransferCheckedWithFee` instead"
138    )]
139    Transfer {
140        /// The amount of tokens to transfer.
141        amount: u64,
142    },
143    /// Approves a delegate.  A delegate is given the authority over tokens on
144    /// behalf of the source account's owner.
145    ///
146    /// Accounts expected by this instruction:
147    ///
148    ///   * Single owner
149    ///   0. `[writable]` The source account.
150    ///   1. `[]` The delegate.
151    ///   2. `[signer]` The source account owner.
152    ///
153    ///   * Multisignature owner
154    ///   0. `[writable]` The source account.
155    ///   1. `[]` The delegate.
156    ///   2. `[]` The source account's multisignature owner.
157    ///   3. ..3+M `[signer]` M signer accounts
158    Approve {
159        /// The amount of tokens the delegate is approved for.
160        amount: u64,
161    },
162    /// Revokes the delegate's authority.
163    ///
164    /// Accounts expected by this instruction:
165    ///
166    ///   * Single owner
167    ///   0. `[writable]` The source account.
168    ///   1. `[signer]` The source account owner or current delegate.
169    ///
170    ///   * Multisignature owner
171    ///   0. `[writable]` The source account.
172    ///   1. `[]` The source account's multisignature owner or current delegate.
173    ///   2. ..2+M `[signer]` M signer accounts
174    Revoke,
175    /// Sets a new authority of a mint or account.
176    ///
177    /// Accounts expected by this instruction:
178    ///
179    ///   * Single authority
180    ///   0. `[writable]` The mint or account to change the authority of.
181    ///   1. `[signer]` The current authority of the mint or account.
182    ///
183    ///   * Multisignature authority
184    ///   0. `[writable]` The mint or account to change the authority of.
185    ///   1. `[]` The mint's or account's current multisignature authority.
186    ///   2. ..2+M `[signer]` M signer accounts
187    SetAuthority {
188        /// The type of authority to update.
189        authority_type: AuthorityType,
190        /// The new authority
191        #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
192        new_authority: COption<Pubkey>,
193    },
194    /// Mints new tokens to an account.  The native mint does not support
195    /// minting.
196    ///
197    /// Accounts expected by this instruction:
198    ///
199    ///   * Single authority
200    ///   0. `[writable]` The mint.
201    ///   1. `[writable]` The account to mint tokens to.
202    ///   2. `[signer]` The mint's minting authority.
203    ///
204    ///   * Multisignature authority
205    ///   0. `[writable]` The mint.
206    ///   1. `[writable]` The account to mint tokens to.
207    ///   2. `[]` The mint's multisignature mint-tokens authority.
208    ///   3. ..3+M `[signer]` M signer accounts.
209    MintTo {
210        /// The amount of new tokens to mint.
211        amount: u64,
212    },
213    /// Burns tokens by removing them from an account.  `Burn` does not support
214    /// accounts associated with the native mint, use `CloseAccount` instead.
215    ///
216    /// Accounts expected by this instruction:
217    ///
218    ///   * Single owner/delegate
219    ///   0. `[writable]` The account to burn from.
220    ///   1. `[writable]` The token mint.
221    ///   2. `[signer]` The account's owner/delegate.
222    ///
223    ///   * Multisignature owner/delegate
224    ///   0. `[writable]` The account to burn from.
225    ///   1. `[writable]` The token mint.
226    ///   2. `[]` The account's multisignature owner/delegate.
227    ///   3. ..3+M `[signer]` M signer accounts.
228    Burn {
229        /// The amount of tokens to burn.
230        amount: u64,
231    },
232    /// Close an account by transferring all its SOL to the destination account.
233    /// Non-native accounts may only be closed if its token amount is zero.
234    ///
235    /// Accounts with the `TransferFeeAmount` extension may only be closed if the withheld
236    /// amount is zero.
237    ///
238    /// Accounts with the `ConfidentialTransfer` extension may only be closed if the pending and
239    /// available balance ciphertexts are empty. Use
240    /// `ConfidentialTransferInstruction::ApplyPendingBalance` and
241    /// `ConfidentialTransferInstruction::EmptyAccount` to empty these ciphertexts.
242    ///
243    /// Accounts with the `ConfidentialTransferFee` extension may only be closed if the withheld
244    /// amount ciphertext is empty. Use
245    /// `ConfidentialTransferFeeInstruction::HarvestWithheldTokensToMint` to empty this ciphertext.
246    ///
247    /// Mints may be closed if they have the `MintCloseAuthority` extension and their token
248    /// supply is zero
249    ///
250    /// Accounts
251    ///
252    /// Accounts expected by this instruction:
253    ///
254    ///   * Single owner
255    ///   0. `[writable]` The account to close.
256    ///   1. `[writable]` The destination account.
257    ///   2. `[signer]` The account's owner.
258    ///
259    ///   * Multisignature owner
260    ///   0. `[writable]` The account to close.
261    ///   1. `[writable]` The destination account.
262    ///   2. `[]` The account's multisignature owner.
263    ///   3. ..3+M `[signer]` M signer accounts.
264    CloseAccount,
265    /// Freeze an Initialized account using the Mint's freeze_authority (if
266    /// set).
267    ///
268    /// Accounts expected by this instruction:
269    ///
270    ///   * Single owner
271    ///   0. `[writable]` The account to freeze.
272    ///   1. `[]` The token mint.
273    ///   2. `[signer]` The mint freeze authority.
274    ///
275    ///   * Multisignature owner
276    ///   0. `[writable]` The account to freeze.
277    ///   1. `[]` The token mint.
278    ///   2. `[]` The mint's multisignature freeze authority.
279    ///   3. ..3+M `[signer]` M signer accounts.
280    FreezeAccount,
281    /// Thaw a Frozen account using the Mint's freeze_authority (if set).
282    ///
283    /// Accounts expected by this instruction:
284    ///
285    ///   * Single owner
286    ///   0. `[writable]` The account to freeze.
287    ///   1. `[]` The token mint.
288    ///   2. `[signer]` The mint freeze authority.
289    ///
290    ///   * Multisignature owner
291    ///   0. `[writable]` The account to freeze.
292    ///   1. `[]` The token mint.
293    ///   2. `[]` The mint's multisignature freeze authority.
294    ///   3. ..3+M `[signer]` M signer accounts.
295    ThawAccount,
296
297    /// Transfers tokens from one account to another either directly or via a
298    /// delegate.  If this account is associated with the native mint then equal
299    /// amounts of SOL and Tokens will be transferred to the destination
300    /// account.
301    ///
302    /// This instruction differs from Transfer in that the token mint and
303    /// decimals value is checked by the caller.  This may be useful when
304    /// creating transactions offline or within a hardware wallet.
305    ///
306    /// If either account contains an `TransferFeeAmount` extension, the fee is
307    /// withheld in the destination account.
308    ///
309    /// Accounts expected by this instruction:
310    ///
311    ///   * Single owner/delegate
312    ///   0. `[writable]` The source account.
313    ///   1. `[]` The token mint.
314    ///   2. `[writable]` The destination account.
315    ///   3. `[signer]` The source account's owner/delegate.
316    ///
317    ///   * Multisignature owner/delegate
318    ///   0. `[writable]` The source account.
319    ///   1. `[]` The token mint.
320    ///   2. `[writable]` The destination account.
321    ///   3. `[]` The source account's multisignature owner/delegate.
322    ///   4. ..4+M `[signer]` M signer accounts.
323    TransferChecked {
324        /// The amount of tokens to transfer.
325        amount: u64,
326        /// Expected number of base 10 digits to the right of the decimal place.
327        decimals: u8,
328    },
329    /// Approves a delegate.  A delegate is given the authority over tokens on
330    /// behalf of the source account's owner.
331    ///
332    /// This instruction differs from Approve in that the token mint and
333    /// decimals value is checked by the caller.  This may be useful when
334    /// creating transactions offline or within a hardware wallet.
335    ///
336    /// Accounts expected by this instruction:
337    ///
338    ///   * Single owner
339    ///   0. `[writable]` The source account.
340    ///   1. `[]` The token mint.
341    ///   2. `[]` The delegate.
342    ///   3. `[signer]` The source account owner.
343    ///
344    ///   * Multisignature owner
345    ///   0. `[writable]` The source account.
346    ///   1. `[]` The token mint.
347    ///   2. `[]` The delegate.
348    ///   3. `[]` The source account's multisignature owner.
349    ///   4. ..4+M `[signer]` M signer accounts
350    ApproveChecked {
351        /// The amount of tokens the delegate is approved for.
352        amount: u64,
353        /// Expected number of base 10 digits to the right of the decimal place.
354        decimals: u8,
355    },
356    /// Mints new tokens to an account.  The native mint does not support
357    /// minting.
358    ///
359    /// This instruction differs from MintTo in that the decimals value is
360    /// checked by the caller.  This may be useful when creating transactions
361    /// offline or within a hardware wallet.
362    ///
363    /// Accounts expected by this instruction:
364    ///
365    ///   * Single authority
366    ///   0. `[writable]` The mint.
367    ///   1. `[writable]` The account to mint tokens to.
368    ///   2. `[signer]` The mint's minting authority.
369    ///
370    ///   * Multisignature authority
371    ///   0. `[writable]` The mint.
372    ///   1. `[writable]` The account to mint tokens to.
373    ///   2. `[]` The mint's multisignature mint-tokens authority.
374    ///   3. ..3+M `[signer]` M signer accounts.
375    MintToChecked {
376        /// The amount of new tokens to mint.
377        amount: u64,
378        /// Expected number of base 10 digits to the right of the decimal place.
379        decimals: u8,
380    },
381    /// Burns tokens by removing them from an account.  `BurnChecked` does not
382    /// support accounts associated with the native mint, use `CloseAccount`
383    /// instead.
384    ///
385    /// This instruction differs from Burn in that the decimals value is checked
386    /// by the caller. This may be useful when creating transactions offline or
387    /// within a hardware wallet.
388    ///
389    /// Accounts expected by this instruction:
390    ///
391    ///   * Single owner/delegate
392    ///   0. `[writable]` The account to burn from.
393    ///   1. `[writable]` The token mint.
394    ///   2. `[signer]` The account's owner/delegate.
395    ///
396    ///   * Multisignature owner/delegate
397    ///   0. `[writable]` The account to burn from.
398    ///   1. `[writable]` The token mint.
399    ///   2. `[]` The account's multisignature owner/delegate.
400    ///   3. ..3+M `[signer]` M signer accounts.
401    BurnChecked {
402        /// The amount of tokens to burn.
403        amount: u64,
404        /// Expected number of base 10 digits to the right of the decimal place.
405        decimals: u8,
406    },
407    /// Like InitializeAccount, but the owner pubkey is passed via instruction data
408    /// rather than the accounts list. This variant may be preferable when using
409    /// Cross Program Invocation from an instruction that does not need the owner's
410    /// `AccountInfo` otherwise.
411    ///
412    /// Accounts expected by this instruction:
413    ///
414    ///   0. `[writable]`  The account to initialize.
415    ///   1. `[]` The mint this account will be associated with.
416    ///   2. `[]` Rent sysvar
417    InitializeAccount2 {
418        /// The new account's owner/multisignature.
419        #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
420        owner: Pubkey,
421    },
422    /// Given a wrapped / native token account (a token account containing SOL)
423    /// updates its amount field based on the account's underlying `lamports`.
424    /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer`
425    /// to move lamports to a wrapped token account, and needs to have its token
426    /// `amount` field updated.
427    ///
428    /// Accounts expected by this instruction:
429    ///
430    ///   0. `[writable]`  The native token account to sync with its underlying lamports.
431    SyncNative,
432    /// Like InitializeAccount2, but does not require the Rent sysvar to be provided
433    ///
434    /// Accounts expected by this instruction:
435    ///
436    ///   0. `[writable]`  The account to initialize.
437    ///   1. `[]` The mint this account will be associated with.
438    InitializeAccount3 {
439        /// The new account's owner/multisignature.
440        #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
441        owner: Pubkey,
442    },
443    /// Like InitializeMultisig, but does not require the Rent sysvar to be provided
444    ///
445    /// Accounts expected by this instruction:
446    ///
447    ///   0. `[writable]` The multisignature account to initialize.
448    ///   1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <=
449    ///      11.
450    InitializeMultisig2 {
451        /// The number of signers (M) required to validate this multisignature
452        /// account.
453        m: u8,
454    },
455    /// Like InitializeMint, but does not require the Rent sysvar to be provided
456    ///
457    /// Accounts expected by this instruction:
458    ///
459    ///   0. `[writable]` The mint to initialize.
460    ///
461    InitializeMint2 {
462        /// Number of base 10 digits to the right of the decimal place.
463        decimals: u8,
464        /// The authority/multisignature to mint tokens.
465        #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
466        mint_authority: Pubkey,
467        /// The freeze authority/multisignature of the mint.
468        #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
469        freeze_authority: COption<Pubkey>,
470    },
471    /// Gets the required size of an account for the given mint as a little-endian
472    /// `u64`.
473    ///
474    /// Return data can be fetched using `sol_get_return_data` and deserializing
475    /// the return data as a little-endian `u64`.
476    ///
477    /// Accounts expected by this instruction:
478    ///
479    ///   0. `[]` The mint to calculate for
480    GetAccountDataSize {
481        /// Additional extension types to include in the returned account size
482        extension_types: Vec<ExtensionType>,
483    },
484    /// Initialize the Immutable Owner extension for the given token account
485    ///
486    /// Fails if the account has already been initialized, so must be called before
487    /// `InitializeAccount`.
488    ///
489    /// Accounts expected by this instruction:
490    ///
491    ///   0. `[writable]`  The account to initialize.
492    ///
493    /// Data expected by this instruction:
494    ///   None
495    ///
496    InitializeImmutableOwner,
497    /// Convert an Amount of tokens to a UiAmount `string`, using the given mint.
498    ///
499    /// Fails on an invalid mint.
500    ///
501    /// Return data can be fetched using `sol_get_return_data` and deserialized with
502    /// `String::from_utf8`.
503    ///
504    /// Accounts expected by this instruction:
505    ///
506    ///   0. `[]` The mint to calculate for
507    AmountToUiAmount {
508        /// The amount of tokens to convert.
509        amount: u64,
510    },
511    /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint.
512    ///
513    /// Return data can be fetched using `sol_get_return_data` and deserializing
514    /// the return data as a little-endian `u64`.
515    ///
516    /// Accounts expected by this instruction:
517    ///
518    ///   0. `[]` The mint to calculate for
519    UiAmountToAmount {
520        /// The ui_amount of tokens to convert.
521        ui_amount: &'a str,
522    },
523    /// Initialize the close account authority on a new mint.
524    ///
525    /// Fails if the mint has already been initialized, so must be called before
526    /// `InitializeMint`.
527    ///
528    /// The mint must have exactly enough space allocated for the base mint (82
529    /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
530    /// then space required for this extension, plus any others.
531    ///
532    /// Accounts expected by this instruction:
533    ///
534    ///   0. `[writable]` The mint to initialize.
535    InitializeMintCloseAuthority {
536        /// Authority that must sign the `CloseAccount` instruction on a mint
537        #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
538        close_authority: COption<Pubkey>,
539    },
540    /// The common instruction prefix for Transfer Fee extension instructions.
541    ///
542    /// See `extension::transfer_fee::instruction::TransferFeeInstruction` for
543    /// further details about the extended instructions that share this instruction prefix
544    TransferFeeExtension(TransferFeeInstruction),
545    /// The common instruction prefix for Confidential Transfer extension instructions.
546    ///
547    /// See `extension::confidential_transfer::instruction::ConfidentialTransferInstruction` for
548    /// further details about the extended instructions that share this instruction prefix
549    ConfidentialTransferExtension,
550    /// The common instruction prefix for Default Account State extension instructions.
551    ///
552    /// See `extension::default_account_state::instruction::DefaultAccountStateInstruction` for
553    /// further details about the extended instructions that share this instruction prefix
554    DefaultAccountStateExtension,
555    /// Check to see if a token account is large enough for a list of ExtensionTypes, and if not,
556    /// use reallocation to increase the data size.
557    ///
558    /// Accounts expected by this instruction:
559    ///
560    ///   * Single owner
561    ///   0. `[writable]` The account to reallocate.
562    ///   1. `[signer, writable]` The payer account to fund reallocation
563    ///   2. `[]` System program for reallocation funding
564    ///   3. `[signer]` The account's owner.
565    ///
566    ///   * Multisignature owner
567    ///   0. `[writable]` The account to reallocate.
568    ///   1. `[signer, writable]` The payer account to fund reallocation
569    ///   2. `[]` System program for reallocation funding
570    ///   3. `[]` The account's multisignature owner/delegate.
571    ///   4. ..4+M `[signer]` M signer accounts.
572    ///
573    Reallocate {
574        /// New extension types to include in the reallocated account
575        extension_types: Vec<ExtensionType>,
576    },
577    /// The common instruction prefix for Memo Transfer account extension instructions.
578    ///
579    /// See `extension::memo_transfer::instruction::RequiredMemoTransfersInstruction` for
580    /// further details about the extended instructions that share this instruction prefix
581    MemoTransferExtension,
582    /// Creates the native mint.
583    ///
584    /// This instruction only needs to be invoked once after deployment and is permissionless,
585    /// Wrapped SOL (`native_mint::id()`) will not be available until this instruction is
586    /// successfully executed.
587    ///
588    /// Accounts expected by this instruction:
589    ///
590    ///   0. `[writeable,signer]` Funding account (must be a system account)
591    ///   1. `[writable]` The native mint address
592    ///   2. `[]` System program for mint account funding
593    ///
594    CreateNativeMint,
595    /// Initialize the non transferable extension for the given mint account
596    ///
597    /// Fails if the account has already been initialized, so must be called before
598    /// `InitializeMint`.
599    ///
600    /// Accounts expected by this instruction:
601    ///
602    ///   0. `[writable]`  The mint account to initialize.
603    ///
604    /// Data expected by this instruction:
605    ///   None
606    ///
607    InitializeNonTransferableMint,
608    /// The common instruction prefix for Interest Bearing extension instructions.
609    ///
610    /// See `extension::interest_bearing_mint::instruction::InterestBearingMintInstruction` for
611    /// further details about the extended instructions that share this instruction prefix
612    InterestBearingMintExtension,
613    /// The common instruction prefix for CPI Guard account extension instructions.
614    ///
615    /// See `extension::cpi_guard::instruction::CpiGuardInstruction` for
616    /// further details about the extended instructions that share this instruction prefix
617    CpiGuardExtension,
618    /// Initialize the permanent delegate on a new mint.
619    ///
620    /// Fails if the mint has already been initialized, so must be called before
621    /// `InitializeMint`.
622    ///
623    /// The mint must have exactly enough space allocated for the base mint (82
624    /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
625    /// then space required for this extension, plus any others.
626    ///
627    /// Accounts expected by this instruction:
628    ///
629    ///   0. `[writable]` The mint to initialize.
630    ///
631    /// Data expected by this instruction:
632    ///   Pubkey for the permanent delegate
633    ///
634    InitializePermanentDelegate {
635        /// Authority that may sign for `Transfer`s and `Burn`s on any account
636        #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
637        delegate: Pubkey,
638    },
639    /// The common instruction prefix for transfer hook extension instructions.
640    ///
641    /// See `extension::transfer_hook::instruction::TransferHookInstruction`
642    /// for further details about the extended instructions that share this instruction
643    /// prefix
644    TransferHookExtension,
645    /// The common instruction prefix for the confidential transfer fee extension instructions.
646    ///
647    /// See `extension::confidential_transfer_fee::instruction::ConfidentialTransferFeeInstruction`
648    /// for further details about the extended instructions that share this instruction prefix
649    ConfidentialTransferFeeExtension,
650    /// This instruction is to be used to rescue SOLs sent to any TokenProgram
651    /// owned account by sending them to any other account, leaving behind only
652    /// lamports for rent exemption.
653    ///
654    /// 0. `[writable]` Source Account owned by the token program
655    /// 1. `[writable]` Destination account
656    /// 2. `[signer]` Authority
657    /// 3. ..2+M `[signer]` M signer accounts.
658    WithdrawExcessLamports,
659    /// The common instruction prefix for metadata pointer extension instructions.
660    ///
661    /// See `extension::metadata_pointer::instruction::MetadataPointerInstruction`
662    /// for further details about the extended instructions that share this instruction
663    /// prefix
664    MetadataPointerExtension,
665}
666impl<'a> TokenInstruction<'a> {
667    /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
668    pub fn unpack(input: &'a [u8]) -> Result<Self, Error> {
669
670        let (&tag, rest) = input.split_first().ok_or(anyhow!("Invalid Instruction"))?;
671        Ok(match tag {
672            0 => {
673                let (&decimals, rest) = rest.split_first().ok_or(anyhow!("Invalid Instruction - 0"))?;
674                let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
675                let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
676                Self::InitializeMint {
677                    mint_authority,
678                    freeze_authority,
679                    decimals,
680                }
681            }
682            1 => Self::InitializeAccount,
683            2 => {
684                let &m = rest.first().ok_or(anyhow!("Invalid Instruction - 2"))?;
685                Self::InitializeMultisig { m }
686            }
687            3 | 4 | 7 | 8 => {
688                let amount = rest
689                    .get(..U64_BYTES)
690                    .and_then(|slice| slice.try_into().ok())
691                    .map(u64::from_le_bytes)
692                    .ok_or(anyhow!("Invalid Instruction - 3 | 4 | 7 | 8"))?;
693                match tag {
694                    #[allow(deprecated)]
695                    3 => Self::Transfer { amount },
696                    4 => Self::Approve { amount },
697                    7 => Self::MintTo { amount },
698                    8 => Self::Burn { amount },
699                    _ => unreachable!(),
700                }
701            }
702            5 => Self::Revoke,
703            6 => {
704                let (authority_type, rest) = rest
705                    .split_first()
706                    .ok_or_else(|| anyhow!("Invalid Instruction - 6"))
707                    .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
708                let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
709
710                Self::SetAuthority {
711                    authority_type,
712                    new_authority,
713                }
714            }
715            9 => Self::CloseAccount,
716            10 => Self::FreezeAccount,
717            11 => Self::ThawAccount,
718            12 => {
719                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
720                Self::TransferChecked { amount, decimals }
721            }
722            13 => {
723                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
724                Self::ApproveChecked { amount, decimals }
725            }
726            14 => {
727                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
728                Self::MintToChecked { amount, decimals }
729            }
730            15 => {
731                let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
732                Self::BurnChecked { amount, decimals }
733            }
734            16 => {
735                let (owner, _rest) = Self::unpack_pubkey(rest)?;
736                Self::InitializeAccount2 { owner }
737            }
738            17 => Self::SyncNative,
739            18 => {
740                let (owner, _rest) = Self::unpack_pubkey(rest)?;
741                Self::InitializeAccount3 { owner }
742            }
743            19 => {
744                let &m = rest.first().ok_or(anyhow!("Invalid Instruction - 19"))?;
745                Self::InitializeMultisig2 { m }
746            }
747            20 => {
748                let (&decimals, rest) = rest.split_first().ok_or(anyhow!("Invalid Instruction - 20"))?;
749                let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
750                let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
751                Self::InitializeMint2 {
752                    mint_authority,
753                    freeze_authority,
754                    decimals,
755                }
756            }
757            21 => {
758                let mut extension_types = vec![];
759                for chunk in rest.chunks(size_of::<ExtensionType>()) {
760                    extension_types.push(chunk.try_into()?);
761                }
762                Self::GetAccountDataSize { extension_types }
763            }
764            22 => Self::InitializeImmutableOwner,
765            23 => {
766                let (amount, _rest) = Self::unpack_u64(rest)?;
767                Self::AmountToUiAmount { amount }
768            }
769            24 => {
770                let ui_amount = std::str::from_utf8(rest).map_err(|_| anyhow!("Invalid Instruction - 24"))?;
771                Self::UiAmountToAmount { ui_amount }
772            }
773            25 => {
774                let (close_authority, _rest) = Self::unpack_pubkey_option(rest)?;
775                Self::InitializeMintCloseAuthority { close_authority }
776            }
777            26 => {
778                let (instruction, _rest) = TransferFeeInstruction::unpack(rest)?;
779                Self::TransferFeeExtension(instruction)
780            }
781            27 => Self::ConfidentialTransferExtension,
782            28 => Self::DefaultAccountStateExtension,
783            29 => {
784                let mut extension_types = vec![];
785                for chunk in rest.chunks(size_of::<ExtensionType>()) {
786                    extension_types.push(chunk.try_into()?);
787                }
788                Self::Reallocate { extension_types }
789            }
790            30 => Self::MemoTransferExtension,
791            31 => Self::CreateNativeMint,
792            32 => Self::InitializeNonTransferableMint,
793            33 => Self::InterestBearingMintExtension,
794            34 => Self::CpiGuardExtension,
795            35 => {
796                let (delegate, _rest) = Self::unpack_pubkey(rest)?;
797                Self::InitializePermanentDelegate { delegate }
798            }
799            36 => Self::TransferHookExtension,
800            37 => Self::ConfidentialTransferFeeExtension,
801            38 => Self::WithdrawExcessLamports,
802            39 => Self::MetadataPointerExtension,
803            _ => return Err(anyhow!("Invalid Instruction - unpack didn't match any tag value: {}", tag)),
804        })
805    }
806
807
808    pub(crate) fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), Error> {
809        let pk = input
810            .get(..PUBKEY_BYTES)
811            .and_then(|x| Pubkey::try_from(x).ok())
812            .ok_or(anyhow!("Unable to unpack pubkey from bytes"))?;
813        Ok((pk, &input[PUBKEY_BYTES..]))
814    }
815
816    pub(crate) fn unpack_pubkey_option(
817        input: &[u8],
818    ) -> Result<(COption<Pubkey>, &[u8]), Error> {
819        match input.split_first() {
820            Option::Some((&0, rest)) => Ok((COption::None, rest)),
821            Option::Some((&1, rest)) => {
822                let (pk, rest) = Self::unpack_pubkey(rest)?;
823                Ok((COption::Some(pk), rest))
824            }
825            _ => Err(anyhow!("unable to unpack pubkey option")),
826        }
827    }
828
829
830    pub(crate) fn unpack_u16(input: &[u8]) -> Result<(u16, &[u8]), Error> {
831        let value = input
832            .get(..U16_BYTES)
833            .and_then(|slice| slice.try_into().ok())
834            .map(u16::from_le_bytes)
835            .ok_or(anyhow!("Unable to unpack u16"))?;
836        Ok((value, &input[U16_BYTES..]))
837    }
838
839    pub(crate) fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), Error> {
840        let value = input
841            .get(..U64_BYTES)
842            .and_then(|slice| slice.try_into().ok())
843            .map(u64::from_le_bytes)
844            .ok_or(anyhow!("Unable to unpack u64"))?;
845        Ok((value, &input[U64_BYTES..]))
846    }
847
848    pub(crate) fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), Error> {
849        let (amount, rest) = Self::unpack_u64(input)?;
850        let (&decimals, rest) = rest.split_first().ok_or(anyhow!("Unable to unpack amount decimals"))?;
851        Ok((amount, decimals, rest))
852    }
853}
854
855/// Specifies the authority type for SetAuthority instructions
856#[repr(u8)]
857#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
858#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
859#[derive(Clone, Debug, PartialEq)]
860pub enum AuthorityType {
861    /// Authority to mint new tokens
862    MintTokens,
863    /// Authority to freeze any account associated with the Mint
864    FreezeAccount,
865    /// Owner of a given token account
866    AccountOwner,
867    /// Authority to close a token account
868    CloseAccount,
869    /// Authority to set the transfer fee
870    TransferFeeConfig,
871    /// Authority to withdraw withheld tokens from a mint
872    WithheldWithdraw,
873    /// Authority to close a mint account
874    CloseMint,
875    /// Authority to set the interest rate
876    InterestRate,
877    /// Authority to transfer or burn any tokens for a mint
878    PermanentDelegate,
879    /// Authority to update confidential transfer mint and aprove accounts for confidential
880    /// transfers
881    ConfidentialTransferMint,
882    /// Authority to set the transfer hook program id
883    TransferHookProgramId,
884    /// Authority to set the withdraw withheld authority encryption key
885    ConfidentialTransferFeeConfig,
886    /// Authority to set the metadata address
887    MetadataPointer,
888}
889
890impl AuthorityType {
891    fn from(index: u8) -> Result<Self, Error> {
892        match index {
893            0 => Ok(AuthorityType::MintTokens),
894            1 => Ok(AuthorityType::FreezeAccount),
895            2 => Ok(AuthorityType::AccountOwner),
896            3 => Ok(AuthorityType::CloseAccount),
897            4 => Ok(AuthorityType::TransferFeeConfig),
898            5 => Ok(AuthorityType::WithheldWithdraw),
899            6 => Ok(AuthorityType::CloseMint),
900            7 => Ok(AuthorityType::InterestRate),
901            8 => Ok(AuthorityType::PermanentDelegate),
902            9 => Ok(AuthorityType::ConfidentialTransferMint),
903            10 => Ok(AuthorityType::TransferHookProgramId),
904            11 => Ok(AuthorityType::ConfidentialTransferFeeConfig),
905            12 => Ok(AuthorityType::MetadataPointer),
906            _ => Err(anyhow!("Invalid Instruction - Invalid AuthorityType with index {}", index)),
907        }
908    }
909}
910
911
912/// Extensions that can be applied to mints or accounts.  Mint extensions must only be
913/// applied to mint accounts, and account extensions must only be applied to token holding
914/// accounts.
915#[repr(u16)]
916#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
917#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
918#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
919pub enum ExtensionType {
920    /// Used as padding if the account size would otherwise be 355, same as a multisig
921    Uninitialized,
922    /// Includes transfer fee rate info and accompanying authorities to withdraw and set the fee
923    TransferFeeConfig,
924    /// Includes withheld transfer fees
925    TransferFeeAmount,
926    /// Includes an optional mint close authority
927    MintCloseAuthority,
928    /// Auditor configuration for confidential transfers
929    ConfidentialTransferMint,
930    /// State for confidential transfers
931    ConfidentialTransferAccount,
932    /// Specifies the default Account::state for new Accounts
933    DefaultAccountState,
934    /// Indicates that the Account owner authority cannot be changed
935    ImmutableOwner,
936    /// Require inbound transfers to have memo
937    MemoTransfer,
938    /// Indicates that the tokens from this mint can't be transfered
939    NonTransferable,
940    /// Tokens accrue interest over time,
941    InterestBearingConfig,
942    /// Locks privileged token operations from happening via CPI
943    CpiGuard,
944    /// Includes an optional permanent delegate
945    PermanentDelegate,
946    /// Indicates that the tokens in this account belong to a non-transferable mint
947    NonTransferableAccount,
948    /// Mint requires a CPI to a program implementing the "transfer hook" interface
949    TransferHook,
950    /// Indicates that the tokens in this account belong to a mint with a transfer hook
951    TransferHookAccount,
952    /// Includes encrypted withheld fees and the encryption public that they are encrypted under
953    ConfidentialTransferFeeConfig,
954    /// Includes confidential withheld transfer fees
955    ConfidentialTransferFeeAmount,
956    /// Mint contains a pointer to another account (or the same account) that holds metadata
957    MetadataPointer,
958    /// Mint contains token-metadata
959    TokenMetadata,
960    /// Test variable-length mint extension
961    #[cfg(test)]
962    VariableLenMintTest = u16::MAX - 2,
963    /// Padding extension used to make an account exactly Multisig::LEN, used for testing
964    #[cfg(test)]
965    AccountPaddingTest,
966    /// Padding extension used to make a mint exactly Multisig::LEN, used for testing
967    #[cfg(test)]
968    MintPaddingTest,
969}
970impl TryFrom<&[u8]> for ExtensionType {
971    type Error = Error;
972    fn try_from(a: &[u8]) -> Result<Self, Self::Error> {
973        Self::try_from(u16::from_le_bytes(
974            a.try_into().map_err(|_| anyhow!("ExtensionType - Invalid extension type from byte"))?,
975        ))
976            .map_err(|_| anyhow!("ExtensionType - try from - Invalid account data"))
977    }
978}
979impl From<ExtensionType> for [u8; 2] {
980    fn from(a: ExtensionType) -> Self {
981        u16::from(a).to_le_bytes()
982    }
983}