diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index e0f747e1..6de462c9 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -477,6 +477,24 @@ pub enum TokenInstruction { /// /// - `&str` The `ui_amount` of tokens to reformat. UiAmountToAmount, + + /// 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 @@ -485,11 +503,10 @@ pub enum TokenInstruction { impl TryFrom for TokenInstruction { type Error = ProgramError; - #[inline(always)] fn try_from(value: u8) -> Result { match value { // SAFETY: `value` is guaranteed to be in the range of the enum variants. - 0..=24 => Ok(unsafe { core::mem::transmute::(value) }), + 0..=24 | 255 => Ok(unsafe { core::mem::transmute::(value) }), _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 63dfb312..d8769984 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -13,7 +13,6 @@ crate-type = ["cdylib"] [features] logging = [] -test-sbf = [] [dependencies] pinocchio = { version = "0.7", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 80fd04ea..4483f023 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -2,7 +2,6 @@ use pinocchio::{ account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use spl_token_interface::instruction::TokenInstruction; use crate::processor::*; @@ -14,218 +13,245 @@ default_panic_handler!(); /// Process an instruction. /// +/// In the first stage, the entrypoint checks the discriminator of the instruction data +/// to determine whether the instruction is a "batch" instruction or a "regular" instruction. +/// This avoids nesting of "batch" instructions, since it is not sound to have a "batch" +/// instruction inside another "batch" instruction. +#[inline(always)] +pub fn process_instruction( + _program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + let [discriminator, remaining @ ..] = instruction_data else { + return Err(ProgramError::InvalidInstructionData); + }; + + if *discriminator == 255 { + // 255 - Batch + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Batch"); + + return process_batch(accounts, remaining); + } + + inner_process_instruction(accounts, instruction_data) +} + +/// Process a "regular" 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: +/// Instructions on the first part of the inner processor: /// -/// - `0`: `InitializeMint` -/// - `3`: `Transfer` -/// - `7`: `MintTo` -/// - `9`: `CloseAccount` +/// - `0`: `InitializeMint` +/// - `1`: `InitializeAccount` +/// - `3`: `Transfer` +/// - `7`: `MintTo` +/// - `9`: `CloseAccount` +/// - `16`: `InitializeAccount2` /// - `18`: `InitializeAccount3` /// - `20`: `InitializeMint2` #[inline(always)] -pub fn process_instruction( - _program_id: &Pubkey, +pub(crate) fn inner_process_instruction( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let (discriminator, instruction_data) = instruction_data - .split_first() - .ok_or(ProgramError::InvalidInstructionData)?; - let instruction = TokenInstruction::try_from(*discriminator)?; + let [discriminator, instruction_data @ ..] = instruction_data else { + return Err(ProgramError::InvalidInstructionData); + }; - match instruction { + match *discriminator { // 0 - InitializeMint - TokenInstruction::InitializeMint => { + 0 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMint"); process_initialize_mint(accounts, instruction_data) } + // 1 - InitializeAccount + 1 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount"); + process_initialize_account(accounts) + } // 3 - Transfer - TokenInstruction::Transfer => { + 3 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Transfer"); process_transfer(accounts, instruction_data) } // 7 - MintTo - TokenInstruction::MintTo => { + 7 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintTo"); process_mint_to(accounts, instruction_data) } // 9 - CloseAccount - TokenInstruction::CloseAccount => { + 9 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: CloseAccount"); process_close_account(accounts) } + // 16 - InitializeAccount2 + 16 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount2"); + + process_initialize_account2(accounts, instruction_data) + } // 18 - InitializeAccount3 - TokenInstruction::InitializeAccount3 => { + 18 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeAccount3"); process_initialize_account3(accounts, instruction_data) } // 20 - InitializeMint2 - TokenInstruction::InitializeMint2 => { + 20 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMint2"); process_initialize_mint2(accounts, instruction_data) } - _ => process_remaining_instruction(accounts, instruction_data, instruction), + d => inner_process_remaining_instruction(accounts, instruction_data, d), } } -/// Process the remaining instructions. +/// Process a remaining "regular" instruction. /// -/// This function is called by the `process_instruction` function if the discriminator +/// This function is called by the [`inner_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( +/// overhead of having a large `match` statement in the [`inner_process_instruction`] function. +fn inner_process_remaining_instruction( accounts: &[AccountInfo], instruction_data: &[u8], - instruction: TokenInstruction, + discriminator: u8, ) -> ProgramResult { - match instruction { - // 1 - InitializeAccount - TokenInstruction::InitializeAccount => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeAccount"); - - process_initialize_account(accounts) - } + match discriminator { // 2 - InitializeMultisig - TokenInstruction::InitializeMultisig => { + 2 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMultisig"); process_initialize_multisig(accounts, instruction_data) } // 4 - Approve - TokenInstruction::Approve => { + 4 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Approve"); process_approve(accounts, instruction_data) } // 5 - Revoke - TokenInstruction::Revoke => { + 5 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Revoke"); process_revoke(accounts, instruction_data) } // 6 - SetAuthority - TokenInstruction::SetAuthority => { + 6 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SetAuthority"); process_set_authority(accounts, instruction_data) } // 8 - Burn - TokenInstruction::Burn => { + 8 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Burn"); process_burn(accounts, instruction_data) } // 10 - FreezeAccount - TokenInstruction::FreezeAccount => { + 10 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: FreezeAccount"); process_freeze_account(accounts) } // 11 - ThawAccount - TokenInstruction::ThawAccount => { + 11 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ThawAccount"); process_thaw_account(accounts) } // 12 - TransferChecked - TokenInstruction::TransferChecked => { + 12 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: TransferChecked"); process_transfer_checked(accounts, instruction_data) } // 13 - ApproveChecked - TokenInstruction::ApproveChecked => { + 13 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ApproveChecked"); process_approve_checked(accounts, instruction_data) } // 14 - MintToChecked - TokenInstruction::MintToChecked => { + 14 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintToChecked"); process_mint_to_checked(accounts, instruction_data) } // 15 - BurnChecked - TokenInstruction::BurnChecked => { + 15 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: BurnChecked"); process_burn_checked(accounts, instruction_data) } - // 16 - InitializeAccount2 - TokenInstruction::InitializeAccount2 => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeAccount2"); - - process_initialize_account2(accounts, instruction_data) - } // 17 - SyncNative - TokenInstruction::SyncNative => { + 17 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SyncNative"); process_sync_native(accounts) } // 19 - InitializeMultisig2 - TokenInstruction::InitializeMultisig2 => { + 19 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMultisig2"); process_initialize_multisig2(accounts, instruction_data) } // 21 - GetAccountDataSize - TokenInstruction::GetAccountDataSize => { + 21 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: GetAccountDataSize"); process_get_account_data_size(accounts) } // 22 - InitializeImmutableOwner - TokenInstruction::InitializeImmutableOwner => { + 22 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeImmutableOwner"); process_initialize_immutable_owner(accounts) } // 23 - AmountToUiAmount - TokenInstruction::AmountToUiAmount => { + 23 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: AmountToUiAmount"); process_amount_to_ui_amount(accounts, instruction_data) } // 24 - UiAmountToAmount - TokenInstruction::UiAmountToAmount => { + 24 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: UiAmountToAmount"); diff --git a/p-token/src/processor/batch.rs b/p-token/src/processor/batch.rs new file mode 100644 index 00000000..6c94208d --- /dev/null +++ b/p-token/src/processor/batch.rs @@ -0,0 +1,57 @@ +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; + +use crate::entrypoint::inner_process_instruction; + +/// The size of the batch instruction header. +/// +/// The header of each instruction consists of two `u8` values: +/// * number of the accounts +/// * length of the instruction data +const IX_HEADER_SIZE: usize = 2; + +pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8]) -> ProgramResult { + loop { + // Validates the instruction data and accounts offset. + + if instruction_data.len() < IX_HEADER_SIZE { + // The instruction data must have at least two bytes. + return Err(ProgramError::InvalidInstructionData); + } + + // SAFETY: The instruction data is guaranteed to have at least two bytes (header) + // + one byte (discriminator). + let expected_accounts = unsafe { *instruction_data.get_unchecked(0) as usize }; + let data_offset = IX_HEADER_SIZE + unsafe { *instruction_data.get_unchecked(1) as usize }; + + if instruction_data.len() < data_offset || data_offset == IX_HEADER_SIZE { + return Err(ProgramError::InvalidInstructionData); + } + + if accounts.len() < expected_accounts { + return Err(ProgramError::NotEnoughAccountKeys); + } + + // Process the instruction. + + // SAFETY: The instruction data and accounts lengths are already validated so all + // slices are guaranteed to be valid. + let (ix_accounts, ix_data) = unsafe { + ( + accounts.get_unchecked(..expected_accounts), + instruction_data.get_unchecked(IX_HEADER_SIZE..data_offset), + ) + }; + + inner_process_instruction(ix_accounts, ix_data)?; + + if data_offset == instruction_data.len() { + // The batch is complete. + break; + } + + accounts = &accounts[expected_accounts..]; + instruction_data = &instruction_data[data_offset..]; + } + + Ok(()) +} diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 96e7586d..0002c0f9 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -16,6 +16,7 @@ use spl_token_interface::{ pub mod amount_to_ui_amount; pub mod approve; pub mod approve_checked; +pub mod batch; pub mod burn; pub mod burn_checked; pub mod close_account; @@ -44,6 +45,7 @@ pub mod shared; pub use amount_to_ui_amount::process_amount_to_ui_amount; pub use approve::process_approve; pub use approve_checked::process_approve_checked; +pub use batch::process_batch; pub use burn::process_burn; pub use burn_checked::process_burn_checked; pub use close_account::process_close_account; diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs index b9d70799..a8de5314 100644 --- a/p-token/tests/amount_to_ui_amount.rs +++ b/p-token/tests/amount_to_ui_amount.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs index b47baa71..dbc606a8 100644 --- a/p-token/tests/approve.rs +++ b/p-token/tests/approve.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index 43c48378..3fb7c75a 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/batch.rs b/p-token/tests/batch.rs new file mode 100644 index 00000000..f2cc481e --- /dev/null +++ b/p-token/tests/batch.rs @@ -0,0 +1,221 @@ +mod setup; + +use crate::setup::TOKEN_PROGRAM_ID; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; + +fn batch_instruction(instructions: Vec) -> Result { + // Create a `Vec` of ordered `AccountMeta`s + let mut accounts: Vec = vec![]; + // Start with the batch discriminator + let mut data: Vec = vec![0xff]; + + for instruction in instructions { + // Error out on non-token IX. + if instruction.program_id.ne(&spl_token::ID) { + return Err(ProgramError::IncorrectProgramId); + } + + data.push(instruction.accounts.len() as u8); + data.push(instruction.data.len() as u8); + + data.extend_from_slice(&instruction.data); + accounts.extend_from_slice(&instruction.accounts); + } + + Ok(Instruction { + program_id: spl_token::ID, + data, + accounts, + }) +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn batch(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let rent = context.banks_client.get_rent().await.unwrap(); + + let mint_len = spl_token::state::Mint::LEN; + let mint_rent = rent.minimum_balance(mint_len); + + let account_len = spl_token::state::Account::LEN; + let account_rent = rent.minimum_balance(account_len); + + // Create a mint + let mint_a = Keypair::new(); + let mint_authority = Keypair::new(); + let create_mint_a = system_instruction::create_account( + &context.payer.pubkey(), + &mint_a.pubkey(), + mint_rent, + mint_len as u64, + &token_program, + ); + let initialize_mint_ix = spl_token::instruction::initialize_mint( + &token_program, + &mint_a.pubkey(), + &mint_authority.pubkey(), + None, + 6, + ) + .unwrap(); + + // Create a mint 2 with a freeze authority + let mint_b = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + let create_mint_b = system_instruction::create_account( + &context.payer.pubkey(), + &mint_b.pubkey(), + mint_rent, + mint_len as u64, + &token_program, + ); + let initialize_mint_with_freeze_authority_ix = spl_token::instruction::initialize_mint2( + &token_program, + &mint_b.pubkey(), + &mint_authority.pubkey(), + Some(&freeze_authority), + 6, + ) + .unwrap(); + + // Create 2 token accounts for mint A and 1 for mint B + let owner_a = Keypair::new(); + let owner_b = Keypair::new(); + let owner_a_ta_a = Keypair::new(); + let owner_b_ta_a = Keypair::new(); + + let create_owner_a_ta_a = system_instruction::create_account( + &context.payer.pubkey(), + &owner_a_ta_a.pubkey(), + account_rent, + account_len as u64, + &token_program, + ); + let create_owner_b_ta_a = system_instruction::create_account( + &context.payer.pubkey(), + &owner_b_ta_a.pubkey(), + account_rent, + account_len as u64, + &token_program, + ); + let intialize_owner_a_ta_a = spl_token::instruction::initialize_account3( + &token_program, + &owner_a_ta_a.pubkey(), + &mint_a.pubkey(), + &owner_a.pubkey(), + ) + .unwrap(); + let intialize_owner_b_ta_a = spl_token::instruction::initialize_account3( + &token_program, + &owner_b_ta_a.pubkey(), + &mint_a.pubkey(), + &owner_b.pubkey(), + ) + .unwrap(); + + // Mint Token A to Owner A + let mint_token_a_to_owner_a = spl_token::instruction::mint_to( + &token_program, + &mint_a.pubkey(), + &owner_a_ta_a.pubkey(), + &mint_authority.pubkey(), + &[], + 1_000_000, + ) + .unwrap(); + + // Transfer Token A from Owner A to Owner B + let transfer_token_a_to_owner_b = spl_token::instruction::transfer( + &token_program, + &owner_a_ta_a.pubkey(), + &owner_b_ta_a.pubkey(), + &owner_a.pubkey(), + &[], + 1_000_000, + ) + .unwrap(); + + // Close Token A + let close_owner_a_ta_a = spl_token::instruction::close_account( + &token_program, + &owner_a_ta_a.pubkey(), + &owner_a.pubkey(), + &owner_a.pubkey(), + &[], + ) + .unwrap(); + + let batch_ix = batch_instruction(vec![ + initialize_mint_ix, + initialize_mint_with_freeze_authority_ix, + intialize_owner_a_ta_a, + intialize_owner_b_ta_a, + mint_token_a_to_owner_a, + transfer_token_a_to_owner_b, + close_owner_a_ta_a, + ]) + .unwrap(); + + let tx = Transaction::new_signed_with_payer( + &[ + create_mint_a, + create_mint_b, + create_owner_a_ta_a, + create_owner_b_ta_a, + batch_ix, + ], + Some(&context.payer.pubkey()), + &vec![ + &context.payer, + &mint_a, + &mint_b, + &owner_a_ta_a, + &owner_b_ta_a, + &mint_authority, + &owner_a, + ], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let mint_a_account = context + .banks_client + .get_account(mint_a.pubkey()) + .await + .unwrap(); + assert!(mint_a_account.is_some()); + let mint_a_account = spl_token::state::Mint::unpack(&mint_a_account.unwrap().data).unwrap(); + assert_eq!(mint_a_account.supply, 1000000); + + let mint_b_account = context + .banks_client + .get_account(mint_b.pubkey()) + .await + .unwrap(); + assert!(mint_b_account.is_some()); + let mint_b_account = spl_token::state::Mint::unpack(&mint_b_account.unwrap().data).unwrap(); + assert_eq!(mint_b_account.supply, 0); + + let owner_b_ta_a_account = context + .banks_client + .get_account(owner_b_ta_a.pubkey()) + .await + .unwrap(); + assert!(owner_b_ta_a_account.is_some()); + let owner_b_ta_a_account = + spl_token::state::Account::unpack(&owner_b_ta_a_account.unwrap().data).unwrap(); + assert_eq!(owner_b_ta_a_account.amount, 1000000); +} diff --git a/p-token/tests/burn.rs b/p-token/tests/burn.rs index df6645d7..67ffb900 100644 --- a/p-token/tests/burn.rs +++ b/p-token/tests/burn.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs index c2256fd9..a28a8b1f 100644 --- a/p-token/tests/burn_checked.rs +++ b/p-token/tests/burn_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/close_account.rs b/p-token/tests/close_account.rs index d4ece1c5..b9ca15a2 100644 --- a/p-token/tests/close_account.rs +++ b/p-token/tests/close_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/freeze_account.rs b/p-token/tests/freeze_account.rs index 2f34b18b..0e8c4983 100644 --- a/p-token/tests/freeze_account.rs +++ b/p-token/tests/freeze_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index 17a2c11c..0980b97f 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_account2.rs b/p-token/tests/initialize_account2.rs index 2ec08051..0e912668 100644 --- a/p-token/tests/initialize_account2.rs +++ b/p-token/tests/initialize_account2.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_account3.rs b/p-token/tests/initialize_account3.rs index c418fc04..a2349aa2 100644 --- a/p-token/tests/initialize_account3.rs +++ b/p-token/tests/initialize_account3.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 94406bd4..4a761a20 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use std::mem::size_of; diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 04ce4d4c..7cf32c50 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use std::mem::size_of; diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 13a518d7..9715545c 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::TOKEN_PROGRAM_ID; diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index 40cf0849..d380b3c8 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::TOKEN_PROGRAM_ID; diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index 75626cbd..96722ac8 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index 56fab40c..f80bd350 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs index 9ba9c7f6..2be0ba20 100644 --- a/p-token/tests/revoke.rs +++ b/p-token/tests/revoke.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs index 8d3f422b..2b500059 100644 --- a/p-token/tests/set_authority.rs +++ b/p-token/tests/set_authority.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs index 4d7f9574..b00506ae 100644 --- a/p-token/tests/thaw_account.rs +++ b/p-token/tests/thaw_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index 357ccb6a..e2bd3771 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index 080bc77e..b599946d 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs index 37a8788d..3e4754cd 100644 --- a/p-token/tests/ui_amount_to_amount.rs +++ b/p-token/tests/ui_amount_to_amount.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/package.json b/package.json index 77a55265..dfcd1075 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "rust:publish": "zx ./scripts/rust/publish.mjs", "rust:semver": "cargo semver-checks", "p-token:build": "zx ./scripts/rust/build-sbf.mjs p-token", - "p-token:test": "zx ./scripts/rust/test-sbf.mjs p-token" + "p-token:test": "zx ./scripts/rust/test.mjs p-token" }, "devDependencies": { "@codama/renderers-js": "^1.2.7",