123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- //! Instruction types.
- use {crate::error::TokenError, pinocchio::program_error::ProgramError};
- /// Instructions supported by the token program.
- #[repr(u8)]
- #[derive(Clone, Debug, PartialEq)]
- #[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))]
- pub enum TokenInstruction {
- /// Initializes a new mint and optionally deposits all the newly minted
- /// tokens in an account.
- ///
- /// The `InitializeMint` instruction requires no signers and MUST be
- /// included within the same Transaction as the system program's
- /// `CreateAccount` instruction that creates the account being initialized.
- /// Otherwise another party can acquire ownership of the uninitialized
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The mint to initialize.
- /// 1. `[]` Rent sysvar.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u8` The number of base 10 digits to the right of the decimal place.
- /// - `Pubkey` The authority/multisignature to mint tokens.
- /// - `Option<Pubkey>` The freeze authority/multisignature of the mint.
- InitializeMint,
- /// Initializes a new account to hold tokens. If this account is associated
- /// with the native mint then the token balance of the initialized account
- /// will be equal to the amount of SOL in the account. If this account is
- /// associated with another mint, that mint must be initialized before this
- /// command can succeed.
- ///
- /// The [`InitializeAccount`] instruction requires no signers and MUST be
- /// included within the same Transaction as the system program's
- /// `CreateAccount` instruction that creates the account being initialized.
- /// Otherwise another party can acquire ownership of the uninitialized
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The account to initialize.
- /// 1. `[]` The mint this account will be associated with.
- /// 2. `[]` The new account's owner/multisignature.
- /// 3. `[]` Rent sysvar.
- InitializeAccount,
- /// Initializes a multisignature account with N provided signers.
- ///
- /// Multisignature accounts can used in place of any single owner/delegate
- /// accounts in any token instruction that require an owner/delegate to be
- /// present. The variant field represents the number of signers (M)
- /// required to validate this multisignature account.
- ///
- /// The [`InitializeMultisig`] instruction requires no signers and MUST be
- /// included within the same Transaction as the system program's
- /// `CreateAccount` instruction that creates the account being initialized.
- /// Otherwise another party can acquire ownership of the uninitialized
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The multisignature account to initialize.
- /// 1. `[]` Rent sysvar.
- /// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <=
- /// N <= 11`.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u8` The number of signers (M) required to validate this
- /// multisignature account.
- InitializeMultisig,
- /// Transfers tokens from one account to another either directly or via a
- /// delegate. If this account is associated with the native mint then equal
- /// amounts of SOL and Tokens will be transferred to the destination
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[writable]` The destination account.
- /// 2. `[signer]` The source account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[writable]` The destination account.
- /// 2. `[]` The source account's multisignature owner/delegate.
- /// 3. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of tokens to transfer.
- Transfer,
- /// Approves a delegate. A delegate is given the authority over tokens on
- /// behalf of the source account's owner.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The delegate.
- /// 2. `[signer]` The source account owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The delegate.
- /// 2. `[]` The source account's multisignature owner.
- /// 3. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of tokens the delegate is approved for.
- Approve,
- /// Revokes the delegate's authority.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The source account.
- /// 1. `[signer]` The source account owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The source account's multisignature owner.
- /// 2. `..+M` `[signer]` M signer accounts.
- Revoke,
- /// Sets a new authority of a mint or account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single authority
- /// 0. `[writable]` The mint or account to change the authority of.
- /// 1. `[signer]` The current authority of the mint or account.
- ///
- /// * Multisignature authority
- /// 0. `[writable]` The mint or account to change the authority of.
- /// 1. `[]` The mint's or account's current multisignature authority.
- /// 2. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `AuthorityType` The type of authority to update.
- /// - `Option<Pubkey>` The new authority.
- SetAuthority,
- /// Mints new tokens to an account. The native mint does not support
- /// minting.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[signer]` The mint's minting authority.
- ///
- /// * Multisignature authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[]` The mint's multisignature mint-tokens authority.
- /// 3. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of new tokens to mint.
- MintTo,
- /// Burns tokens by removing them from an account. `Burn` does not support
- /// accounts associated with the native mint, use `CloseAccount` instead.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[signer]` The account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[]` The account's multisignature owner/delegate.
- /// 3. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of tokens to burn.
- Burn,
- /// Close an account by transferring all its SOL to the destination account.
- /// Non-native accounts may only be closed if its token amount is zero.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The account to close.
- /// 1. `[writable]` The destination account.
- /// 2. `[signer]` The account's owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The account to close.
- /// 1. `[writable]` The destination account.
- /// 2. `[]` The account's multisignature owner.
- /// 3. `..+M` `[signer]` M signer accounts.
- CloseAccount,
- /// Freeze an Initialized account using the Mint's [`freeze_authority`] (if
- /// set).
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[signer]` The mint freeze authority.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[]` The mint's multisignature freeze authority.
- /// 3. `..+M` `[signer]` M signer accounts.
- FreezeAccount,
- /// Thaw a Frozen account using the Mint's [`freeze_authority`] (if set).
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[signer]` The mint freeze authority.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[]` The mint's multisignature freeze authority.
- /// 3. `..+M` `[signer]` M signer accounts.
- ThawAccount,
- /// Transfers tokens from one account to another either directly or via a
- /// delegate. If this account is associated with the native mint then equal
- /// amounts of SOL and Tokens will be transferred to the destination
- /// account.
- ///
- /// This instruction differs from Transfer in that the token mint and
- /// decimals value is checked by the caller. This may be useful when
- /// creating transactions offline or within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[writable]` The destination account.
- /// 3. `[signer]` The source account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[writable]` The destination account.
- /// 3. `[]` The source account's multisignature owner/delegate.
- /// 4. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of tokens to transfer.
- /// - `u8` Expected number of base 10 digits to the right of the decimal
- /// place.
- TransferChecked,
- /// Approves a delegate. A delegate is given the authority over tokens on
- /// behalf of the source account's owner.
- ///
- /// This instruction differs from Approve in that the token mint and
- /// decimals value is checked by the caller. This may be useful when
- /// creating transactions offline or within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[]` The delegate.
- /// 3. `[signer]` The source account owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[]` The delegate.
- /// 3. `[]` The source account's multisignature owner.
- /// 4. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of tokens the delegate is approved for.
- /// - `u8` Expected number of base 10 digits to the right of the decimal
- /// place.
- ApproveChecked,
- /// Mints new tokens to an account. The native mint does not support
- /// minting.
- ///
- /// This instruction differs from [`MintTo`] in that the decimals value is
- /// checked by the caller. This may be useful when creating transactions
- /// offline or within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[signer]` The mint's minting authority.
- ///
- /// * Multisignature authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[]` The mint's multisignature mint-tokens authority.
- /// 3. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of new tokens to mint.
- /// - `u8` Expected number of base 10 digits to the right of the decimal
- /// place.
- MintToChecked,
- /// Burns tokens by removing them from an account. [`BurnChecked`] does not
- /// support accounts associated with the native mint, use `CloseAccount`
- /// instead.
- ///
- /// This instruction differs from Burn in that the decimals value is checked
- /// by the caller. This may be useful when creating transactions offline or
- /// within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[signer]` The account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[]` The account's multisignature owner/delegate.
- /// 3. `..+M` `[signer]` M signer accounts.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of tokens to burn.
- /// - `u8` Expected number of base 10 digits to the right of the decimal
- /// place.
- BurnChecked,
- /// Like [`InitializeAccount`], but the owner pubkey is passed via
- /// instruction data rather than the accounts list. This variant may be
- /// preferable when using Cross Program Invocation from an instruction
- /// that does not need the owner's `AccountInfo` otherwise.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The account to initialize.
- /// 1. `[]` The mint this account will be associated with.
- /// 2. `[]` Rent sysvar.
- ///
- /// Data expected by this instruction:
- ///
- /// - `Pubkey` The new account's owner/multisignature.
- InitializeAccount2,
- /// Given a wrapped / native token account (a token account containing SOL)
- /// updates its amount field based on the account's underlying `lamports`.
- /// This is useful if a non-wrapped SOL account uses
- /// `system_instruction::transfer` to move lamports to a wrapped token
- /// account, and needs to have its token `amount` field updated.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The native token account to sync with its underlying
- /// lamports.
- SyncNative,
- /// Like [`InitializeAccount2`], but does not require the Rent sysvar to be
- /// provided
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The account to initialize.
- /// 1. `[]` The mint this account will be associated with.
- ///
- /// Data expected by this instruction:
- ///
- /// - `Pubkey` The new account's owner/multisignature.
- InitializeAccount3,
- /// Like [`InitializeMultisig`], but does not require the Rent sysvar to be
- /// provided
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The multisignature account to initialize.
- /// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <=
- /// N <= 11`.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u8` The number of signers (M) required to validate this
- /// multisignature account.
- InitializeMultisig2,
- /// Like [`InitializeMint`], but does not require the Rent sysvar to be
- /// provided
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The mint to initialize.
- ///
- /// Data expected by this instruction:
- ///
- /// - `u8` The number of base 10 digits to the right of the decimal place.
- /// - `Pubkey` The authority/multisignature to mint tokens.
- /// - `Option<Pubkey>` The freeze authority/multisignature of the mint.
- InitializeMint2,
- /// Gets the required size of an account for the given mint as a
- /// little-endian `u64`.
- ///
- /// Return data can be fetched using `sol_get_return_data` and deserializing
- /// the return data as a little-endian `u64`.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[]` The mint to calculate for.
- GetAccountDataSize,
- /// Initialize the Immutable Owner extension for the given token account
- ///
- /// Fails if the account has already been initialized, so must be called
- /// before [`InitializeAccount`].
- ///
- /// No-ops in this version of the program, but is included for compatibility
- /// with the Associated Token Account program.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The account to initialize.
- InitializeImmutableOwner,
- /// Convert an Amount of tokens to a `UiAmount` `string`, using the given
- /// mint. In this version of the program, the mint can only specify the
- /// number of decimals.
- ///
- /// Fails on an invalid mint.
- ///
- /// Return data can be fetched using `sol_get_return_data` and deserialized
- /// with `String::from_utf8`.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[]` The mint to calculate for
- ///
- /// Data expected by this instruction:
- ///
- /// - `u64` The amount of tokens to reformat.
- AmountToUiAmount,
- /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount,
- /// using the given mint. In this version of the program, the mint can
- /// only specify the number of decimals.
- ///
- /// Return data can be fetched using `sol_get_return_data` and deserializing
- /// the return data as a little-endian `u64`.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[]` The mint to calculate for.
- ///
- /// Data expected by this instruction:
- ///
- /// - `&str` The `ui_amount` of tokens to reformat.
- UiAmountToAmount,
- /// This instruction is to be used to rescue SOL sent to any `TokenProgram`
- /// owned account by sending them to any other account, leaving behind only
- /// lamports for rent exemption.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` Source Account owned by the token program
- /// 1. `[writable]` Destination account
- /// 2. `[signer]` Authority
- /// 3. `..+M` `[signer]` M signer accounts.
- WithdrawExcessLamports = 38,
- /// Executes a batch of instructions. The instructions to be executed are
- /// specified in sequence on the instruction data. Each instruction
- /// provides:
- /// - `u8`: number of accounts
- /// - `u8`: instruction data length (includes the discriminator)
- /// - `u8`: instruction discriminator
- /// - `[u8]`: instruction data
- ///
- /// Accounts follow a similar pattern, where accounts for each instruction
- /// are specified in sequence. Therefore, the number of accounts
- /// expected by this instruction is variable, i.e., it depends on the
- /// instructions provided.
- ///
- /// Both the number of accounts and instruction data length are used to
- /// identify the slice of accounts and instruction data for each
- /// instruction.
- ///
- /// Note that it is not sound to have a `batch` instruction that contains
- /// other `batch` instruction; an error will be raised when this is
- /// detected.
- Batch = 255,
- // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the
- // latter remains a superset of this instruction set. New variants also need to be added to
- // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility
- }
- impl TryFrom<u8> for TokenInstruction {
- type Error = ProgramError;
- fn try_from(value: u8) -> Result<Self, Self::Error> {
- match value {
- // SAFETY: `value` is guaranteed to be in the range of the enum variants.
- 0..=24 | 38 | 255 => Ok(unsafe { core::mem::transmute::<u8, TokenInstruction>(value) }),
- _ => Err(TokenError::InvalidInstruction.into()),
- }
- }
- }
- /// Specifies the authority type for `SetAuthority` instructions
- #[repr(u8)]
- #[derive(Clone, Debug, PartialEq)]
- #[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))]
- pub enum AuthorityType {
- /// Authority to mint new tokens
- MintTokens,
- /// Authority to freeze any account associated with the Mint
- FreezeAccount,
- /// Owner of a given token account
- AccountOwner,
- /// Authority to close a token account
- CloseAccount,
- }
- impl TryFrom<u8> for AuthorityType {
- type Error = ProgramError;
- #[inline(always)]
- fn try_from(value: u8) -> Result<Self, Self::Error> {
- match value {
- // SAFETY: `value` is guaranteed to be in the range of the enum variants.
- 0..=3 => Ok(unsafe { core::mem::transmute::<u8, AuthorityType>(value) }),
- _ => Err(TokenError::InvalidInstruction.into()),
- }
- }
- }
- #[cfg(test)]
- mod tests {
- use {
- super::{AuthorityType, TokenInstruction},
- strum::IntoEnumIterator,
- };
- #[test]
- fn test_token_instruction_from_u8_exhaustive() {
- for variant in TokenInstruction::iter() {
- let variant_u8 = variant.clone() as u8;
- assert_eq!(
- TokenInstruction::from_repr(variant_u8),
- Some(TokenInstruction::try_from(variant_u8).unwrap())
- );
- assert_eq!(TokenInstruction::try_from(variant_u8).unwrap(), variant);
- }
- }
- #[test]
- fn test_authority_type_from_u8_exhaustive() {
- for variant in AuthorityType::iter() {
- let variant_u8 = variant.clone() as u8;
- assert_eq!(
- AuthorityType::from_repr(variant_u8),
- Some(AuthorityType::try_from(variant_u8).unwrap())
- );
- assert_eq!(AuthorityType::try_from(variant_u8).unwrap(), variant);
- }
- }
- }
|