|
@@ -1,276 +1,229 @@
|
|
|
-use core::str;
|
|
|
-
|
|
|
use pinocchio::{
|
|
|
account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey,
|
|
|
ProgramResult,
|
|
|
};
|
|
|
|
|
|
-use crate::processor::{
|
|
|
- amount_to_ui_amount::process_amount_to_ui_amount,
|
|
|
- approve::process_approve,
|
|
|
- approve_checked::{process_approve_checked, ApproveChecked},
|
|
|
- burn::process_burn,
|
|
|
- burn_checked::{process_burn_checked, BurnChecked},
|
|
|
- close_account::process_close_account,
|
|
|
- freeze_account::process_freeze_account,
|
|
|
- get_account_data_size::process_get_account_data_size,
|
|
|
- initialize_account::process_initialize_account,
|
|
|
- initialize_account2::process_initialize_account2,
|
|
|
- initialize_account3::process_initialize_account3,
|
|
|
- initialize_immutable_owner::process_initialize_immutable_owner,
|
|
|
- initialize_mint::process_initialize_mint,
|
|
|
- initialize_mint2::process_initialize_mint2,
|
|
|
- initialize_multisig::process_initialize_multisig,
|
|
|
- initialize_multisig2::process_initialize_multisig2,
|
|
|
- mint_to::process_mint_to,
|
|
|
- mint_to_checked::{process_mint_to_checked, MintToChecked},
|
|
|
- revoke::process_revoke,
|
|
|
- set_authority::{process_set_authority, SetAuthority},
|
|
|
- shared::initialize_mint::InitializeMint,
|
|
|
- sync_native::process_sync_native,
|
|
|
- thaw_account::process_thaw_account,
|
|
|
- transfer::process_transfer,
|
|
|
- transfer_checked::{process_transfer_checked, TransferChecked},
|
|
|
- ui_amount_to_amount::process_ui_amount_to_amount,
|
|
|
-};
|
|
|
+use crate::processor::*;
|
|
|
|
|
|
entrypoint!(process_instruction);
|
|
|
|
|
|
+/// Process an instruction.
|
|
|
+///
|
|
|
+/// The processor of the token program is divided into two parts to reduce the overhead
|
|
|
+/// of having a large `match` statement. The first part of the processor handles the
|
|
|
+/// most common instructions, while the second part handles the remaining instructions.
|
|
|
+/// The rationale is to reduce the overhead of making multiple comparisons for popular
|
|
|
+/// instructions.
|
|
|
+///
|
|
|
+/// Instructions on the first part of the processor:
|
|
|
+///
|
|
|
+/// - `0`: `InitializeMint`
|
|
|
+/// - `3`: `Transfer`
|
|
|
+/// - `7`: `MintTo`
|
|
|
+/// - `9`: `CloseAccount`
|
|
|
+/// - `18`: `InitializeAccount3`
|
|
|
+/// - `20`: `InitializeMint2`
|
|
|
#[inline(always)]
|
|
|
pub fn process_instruction(
|
|
|
- program_id: &Pubkey,
|
|
|
+ _program_id: &Pubkey,
|
|
|
accounts: &[AccountInfo],
|
|
|
instruction_data: &[u8],
|
|
|
) -> ProgramResult {
|
|
|
- match instruction_data.split_first() {
|
|
|
+ let (discriminator, instruction_data) = instruction_data
|
|
|
+ .split_first()
|
|
|
+ .ok_or(ProgramError::InvalidInstructionData)?;
|
|
|
+
|
|
|
+ match *discriminator {
|
|
|
// 0 - InitializeMint
|
|
|
- Some((&0, data)) => {
|
|
|
+ 0 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: InitializeMint");
|
|
|
|
|
|
- let instruction = InitializeMint::try_from_bytes(data)?;
|
|
|
+ process_initialize_mint(accounts, instruction_data, true)
|
|
|
+ }
|
|
|
|
|
|
- process_initialize_mint(accounts, &instruction)
|
|
|
+ // 3 - Transfer
|
|
|
+ 3 => {
|
|
|
+ #[cfg(feature = "logging")]
|
|
|
+ pinocchio::msg!("Instruction: Transfer");
|
|
|
+
|
|
|
+ process_transfer(accounts, instruction_data)
|
|
|
}
|
|
|
- // 1 - InitializeAccount
|
|
|
- Some((&1, _)) => {
|
|
|
+ // 7 - MintTo
|
|
|
+ 7 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
- pinocchio::msg!("Instruction: InitializeAccount");
|
|
|
+ pinocchio::msg!("Instruction: MintTo");
|
|
|
|
|
|
- process_initialize_account(program_id, accounts)
|
|
|
+ process_mint_to(accounts, instruction_data)
|
|
|
}
|
|
|
- // 2 - InitializeMultisig
|
|
|
- Some((&2, data)) => {
|
|
|
+ // 9 - CloseAccount
|
|
|
+ 9 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
- pinocchio::msg!("Instruction: InitializeMultisig");
|
|
|
+ pinocchio::msg!("Instruction: CloseAccount");
|
|
|
+
|
|
|
+ process_close_account(accounts)
|
|
|
+ }
|
|
|
+ // 18 - InitializeAccount3
|
|
|
+ 18 => {
|
|
|
+ #[cfg(feature = "logging")]
|
|
|
+ pinocchio::msg!("Instruction: InitializeAccount3");
|
|
|
|
|
|
- let m = data.first().ok_or(ProgramError::InvalidInstructionData)?;
|
|
|
+ process_initialize_account3(accounts, instruction_data)
|
|
|
+ }
|
|
|
+ // 20 - InitializeMint2
|
|
|
+ 20 => {
|
|
|
+ #[cfg(feature = "logging")]
|
|
|
+ pinocchio::msg!("Instruction: InitializeMint2");
|
|
|
|
|
|
- process_initialize_multisig(accounts, *m, true)
|
|
|
+ process_initialize_mint2(accounts, instruction_data)
|
|
|
}
|
|
|
- // 3 - Transfer
|
|
|
- Some((&3, data)) => {
|
|
|
+ _ => process_remaining_instruction(accounts, instruction_data, *discriminator),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// Process the remaining instructions.
|
|
|
+///
|
|
|
+/// This function is called by the `process_instruction` function if the discriminator
|
|
|
+/// does not match any of the common instructions. This function is used to reduce the
|
|
|
+/// overhead of having a large `match` statement in the `process_instruction` function.
|
|
|
+fn process_remaining_instruction(
|
|
|
+ accounts: &[AccountInfo],
|
|
|
+ instruction_data: &[u8],
|
|
|
+ discriminator: u8,
|
|
|
+) -> ProgramResult {
|
|
|
+ match discriminator {
|
|
|
+ // 1 - InitializeAccount
|
|
|
+ 1 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
- pinocchio::msg!("Instruction: Transfer");
|
|
|
+ pinocchio::msg!("Instruction: InitializeAccount");
|
|
|
|
|
|
- let amount = u64::from_le_bytes(
|
|
|
- data.try_into()
|
|
|
- .map_err(|_error| ProgramError::InvalidInstructionData)?,
|
|
|
- );
|
|
|
+ process_initialize_account(accounts)
|
|
|
+ }
|
|
|
+ // 2 - InitializeMultisig
|
|
|
+ 2 => {
|
|
|
+ #[cfg(feature = "logging")]
|
|
|
+ pinocchio::msg!("Instruction: InitializeMultisig");
|
|
|
|
|
|
- process_transfer(program_id, accounts, amount)
|
|
|
+ process_initialize_multisig(accounts, instruction_data)
|
|
|
}
|
|
|
// 4 - Approve
|
|
|
- Some((&4, data)) => {
|
|
|
+ 4 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: Approve");
|
|
|
|
|
|
- let amount = u64::from_le_bytes(
|
|
|
- data.try_into()
|
|
|
- .map_err(|_error| ProgramError::InvalidInstructionData)?,
|
|
|
- );
|
|
|
-
|
|
|
- process_approve(program_id, accounts, amount)
|
|
|
+ process_approve(accounts, instruction_data)
|
|
|
}
|
|
|
// 5 - Revoke
|
|
|
- Some((&5, _)) => {
|
|
|
+ 5 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: Revoke");
|
|
|
|
|
|
- process_revoke(program_id, accounts)
|
|
|
+ process_revoke(accounts, instruction_data)
|
|
|
}
|
|
|
// 6 - SetAuthority
|
|
|
- Some((&6, data)) => {
|
|
|
+ 6 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: SetAuthority");
|
|
|
|
|
|
- let instruction = SetAuthority::try_from_bytes(data)?;
|
|
|
- process_set_authority(
|
|
|
- program_id,
|
|
|
- accounts,
|
|
|
- instruction.authority_type,
|
|
|
- instruction.new_authority,
|
|
|
- )
|
|
|
- }
|
|
|
- // 7 - MintTo
|
|
|
- Some((&7, data)) => {
|
|
|
- #[cfg(feature = "logging")]
|
|
|
- pinocchio::msg!("Instruction: MintTo");
|
|
|
-
|
|
|
- let amount = u64::from_le_bytes(
|
|
|
- data.try_into()
|
|
|
- .map_err(|_error| ProgramError::InvalidInstructionData)?,
|
|
|
- );
|
|
|
-
|
|
|
- process_mint_to(program_id, accounts, amount)
|
|
|
+ process_set_authority(accounts, instruction_data)
|
|
|
}
|
|
|
// 8 - Burn
|
|
|
- Some((&8, data)) => {
|
|
|
+ 8 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: Burn");
|
|
|
|
|
|
- let amount = u64::from_le_bytes(
|
|
|
- data.try_into()
|
|
|
- .map_err(|_error| ProgramError::InvalidInstructionData)?,
|
|
|
- );
|
|
|
-
|
|
|
- process_burn(program_id, accounts, amount)
|
|
|
- }
|
|
|
- // 9 - CloseAccount
|
|
|
- Some((&9, _)) => {
|
|
|
- #[cfg(feature = "logging")]
|
|
|
- pinocchio::msg!("Instruction: CloseAccount");
|
|
|
-
|
|
|
- process_close_account(program_id, accounts)
|
|
|
+ process_burn(accounts, instruction_data)
|
|
|
}
|
|
|
// 10 - FreezeAccount
|
|
|
- Some((&10, _)) => {
|
|
|
+ 10 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: FreezeAccount");
|
|
|
|
|
|
- process_freeze_account(program_id, accounts)
|
|
|
+ process_freeze_account(accounts)
|
|
|
}
|
|
|
// 11 - ThawAccount
|
|
|
- Some((&11, _)) => {
|
|
|
+ 11 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: ThawAccount");
|
|
|
|
|
|
- process_thaw_account(program_id, accounts)
|
|
|
+ process_thaw_account(accounts)
|
|
|
}
|
|
|
// 12 - TransferChecked
|
|
|
- Some((&12, data)) => {
|
|
|
+ 12 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: TransferChecked");
|
|
|
|
|
|
- let args = TransferChecked::try_from_bytes(data)?;
|
|
|
-
|
|
|
- process_transfer_checked(program_id, accounts, args.amount(), args.decimals())
|
|
|
+ process_transfer_checked(accounts, instruction_data)
|
|
|
}
|
|
|
// 13 - ApproveChecked
|
|
|
- Some((&13, data)) => {
|
|
|
+ 13 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: ApproveChecked");
|
|
|
|
|
|
- let args = ApproveChecked::try_from_bytes(data)?;
|
|
|
-
|
|
|
- process_approve_checked(program_id, accounts, args.amount(), args.decimals())
|
|
|
+ process_approve_checked(accounts, instruction_data)
|
|
|
}
|
|
|
// 14 - MintToChecked
|
|
|
- Some((&14, data)) => {
|
|
|
+ 14 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: MintToChecked");
|
|
|
|
|
|
- let args = MintToChecked::try_from_bytes(data)?;
|
|
|
-
|
|
|
- process_mint_to_checked(program_id, accounts, args.amount(), args.decimals())
|
|
|
+ process_mint_to_checked(accounts, instruction_data)
|
|
|
}
|
|
|
// 15 - BurnChecked
|
|
|
- Some((&15, data)) => {
|
|
|
+ 15 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: BurnChecked");
|
|
|
|
|
|
- let args = BurnChecked::try_from_bytes(data)?;
|
|
|
-
|
|
|
- process_burn_checked(program_id, accounts, args.amount(), args.decimals())
|
|
|
+ process_burn_checked(accounts, instruction_data)
|
|
|
}
|
|
|
// 16 - InitializeAccount2
|
|
|
- Some((&16, data)) => {
|
|
|
+ 16 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: InitializeAccount2");
|
|
|
|
|
|
- let owner = unsafe { &*(data.as_ptr() as *const Pubkey) };
|
|
|
-
|
|
|
- process_initialize_account2(program_id, accounts, owner)
|
|
|
+ process_initialize_account2(accounts, instruction_data)
|
|
|
}
|
|
|
// 17 - SyncNative
|
|
|
- Some((&17, _)) => {
|
|
|
+ 17 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: SyncNative");
|
|
|
|
|
|
- process_sync_native(program_id, accounts)
|
|
|
- }
|
|
|
- // 18 - InitializeAccount3
|
|
|
- Some((&18, data)) => {
|
|
|
- #[cfg(feature = "logging")]
|
|
|
- pinocchio::msg!("Instruction: InitializeAccount3");
|
|
|
-
|
|
|
- let owner = unsafe { &*(data.as_ptr() as *const Pubkey) };
|
|
|
-
|
|
|
- process_initialize_account3(program_id, accounts, owner)
|
|
|
+ process_sync_native(accounts)
|
|
|
}
|
|
|
// 19 - InitializeMultisig2
|
|
|
- Some((&19, data)) => {
|
|
|
+ 19 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: InitializeMultisig2");
|
|
|
|
|
|
- let m = data.first().ok_or(ProgramError::InvalidInstructionData)?;
|
|
|
-
|
|
|
- process_initialize_multisig2(accounts, *m)
|
|
|
- }
|
|
|
- // 20 - InitializeMint2
|
|
|
- Some((&20, data)) => {
|
|
|
- #[cfg(feature = "logging")]
|
|
|
- pinocchio::msg!("Instruction: InitializeMint2");
|
|
|
-
|
|
|
- let instruction = InitializeMint::try_from_bytes(data)?;
|
|
|
-
|
|
|
- process_initialize_mint2(accounts, &instruction)
|
|
|
+ process_initialize_multisig2(accounts, instruction_data)
|
|
|
}
|
|
|
// 21 - GetAccountDataSize
|
|
|
- Some((&21, _)) => {
|
|
|
+ 21 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: GetAccountDataSize");
|
|
|
|
|
|
- process_get_account_data_size(program_id, accounts)
|
|
|
+ process_get_account_data_size(accounts)
|
|
|
}
|
|
|
// 22 - InitializeImmutableOwner
|
|
|
- Some((&22, _)) => {
|
|
|
+ 22 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: InitializeImmutableOwner");
|
|
|
|
|
|
process_initialize_immutable_owner(accounts)
|
|
|
}
|
|
|
// 23 - AmountToUiAmount
|
|
|
- Some((&23, data)) => {
|
|
|
+ 23 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: AmountToUiAmount");
|
|
|
|
|
|
- let amount = u64::from_le_bytes(
|
|
|
- data.try_into()
|
|
|
- .map_err(|_error| ProgramError::InvalidInstructionData)?,
|
|
|
- );
|
|
|
-
|
|
|
- process_amount_to_ui_amount(program_id, accounts, amount)
|
|
|
+ process_amount_to_ui_amount(accounts, instruction_data)
|
|
|
}
|
|
|
// 24 - UiAmountToAmount
|
|
|
- Some((&24, data)) => {
|
|
|
+ 24 => {
|
|
|
#[cfg(feature = "logging")]
|
|
|
pinocchio::msg!("Instruction: UiAmountToAmount");
|
|
|
|
|
|
- let ui_amount =
|
|
|
- str::from_utf8(data).map_err(|_error| ProgramError::InvalidInstructionData)?;
|
|
|
-
|
|
|
- process_ui_amount_to_amount(program_id, accounts, ui_amount)
|
|
|
+ process_ui_amount_to_amount(accounts, instruction_data)
|
|
|
}
|
|
|
_ => Err(ProgramError::InvalidInstructionData),
|
|
|
}
|