diff --git a/token/program-2022/src/extension/confidential_transfer/processor.rs b/token/program-2022/src/extension/confidential_transfer/processor.rs index 13e63bf5566..f6e868290b8 100644 --- a/token/program-2022/src/extension/confidential_transfer/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer/processor.rs @@ -18,7 +18,8 @@ use { }, memo_transfer::{check_previous_sibling_instruction_is_memo, memo_required}, transfer_fee::TransferFeeConfig, - BaseStateWithExtensions, StateWithExtensions, StateWithExtensionsMut, + BaseStateWithExtensions, BaseStateWithExtensionsMut, StateWithExtensions, + StateWithExtensionsMut, }, instruction::{decode_instruction_data, decode_instruction_type}, processor::Processor, diff --git a/token/program-2022/src/extension/confidential_transfer_fee/processor.rs b/token/program-2022/src/extension/confidential_transfer_fee/processor.rs index d3b2ba78eef..f40f9ffc6a8 100644 --- a/token/program-2022/src/extension/confidential_transfer_fee/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer_fee/processor.rs @@ -24,7 +24,7 @@ use { EncryptedWithheldAmount, }, transfer_fee::TransferFeeConfig, - BaseStateWithExtensions, StateWithExtensionsMut, + BaseStateWithExtensions, BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::{decode_instruction_data, decode_instruction_type}, processor::Processor, diff --git a/token/program-2022/src/extension/cpi_guard/processor.rs b/token/program-2022/src/extension/cpi_guard/processor.rs index 3419a27358b..edee5cd02fa 100644 --- a/token/program-2022/src/extension/cpi_guard/processor.rs +++ b/token/program-2022/src/extension/cpi_guard/processor.rs @@ -4,7 +4,7 @@ use { error::TokenError, extension::{ cpi_guard::{in_cpi, instruction::CpiGuardInstruction, CpiGuard}, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::decode_instruction_type, processor::Processor, diff --git a/token/program-2022/src/extension/default_account_state/processor.rs b/token/program-2022/src/extension/default_account_state/processor.rs index becc9fa8ee3..f50d593d476 100644 --- a/token/program-2022/src/extension/default_account_state/processor.rs +++ b/token/program-2022/src/extension/default_account_state/processor.rs @@ -7,7 +7,7 @@ use { instruction::{decode_instruction, DefaultAccountStateInstruction}, DefaultAccountState, }, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, processor::Processor, state::{AccountState, Mint}, diff --git a/token/program-2022/src/extension/group_member_pointer/processor.rs b/token/program-2022/src/extension/group_member_pointer/processor.rs index 87fd530deb6..7e5e984b54c 100644 --- a/token/program-2022/src/extension/group_member_pointer/processor.rs +++ b/token/program-2022/src/extension/group_member_pointer/processor.rs @@ -9,7 +9,7 @@ use { }, GroupMemberPointer, }, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::{decode_instruction_data, decode_instruction_type}, processor::Processor, diff --git a/token/program-2022/src/extension/group_pointer/processor.rs b/token/program-2022/src/extension/group_pointer/processor.rs index 07a8c96766e..655ee9b0181 100644 --- a/token/program-2022/src/extension/group_pointer/processor.rs +++ b/token/program-2022/src/extension/group_pointer/processor.rs @@ -9,7 +9,7 @@ use { }, GroupPointer, }, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::{decode_instruction_data, decode_instruction_type}, processor::Processor, diff --git a/token/program-2022/src/extension/interest_bearing_mint/processor.rs b/token/program-2022/src/extension/interest_bearing_mint/processor.rs index 2ef0411a813..38f509c0a6b 100644 --- a/token/program-2022/src/extension/interest_bearing_mint/processor.rs +++ b/token/program-2022/src/extension/interest_bearing_mint/processor.rs @@ -7,7 +7,7 @@ use { instruction::{InitializeInstructionData, InterestBearingMintInstruction}, BasisPoints, InterestBearingConfig, }, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::{decode_instruction_data, decode_instruction_type}, processor::Processor, diff --git a/token/program-2022/src/extension/memo_transfer/processor.rs b/token/program-2022/src/extension/memo_transfer/processor.rs index e699e0d1a5c..6e65e1c36d2 100644 --- a/token/program-2022/src/extension/memo_transfer/processor.rs +++ b/token/program-2022/src/extension/memo_transfer/processor.rs @@ -3,7 +3,7 @@ use { check_program_account, extension::{ memo_transfer::{instruction::RequiredMemoTransfersInstruction, MemoTransfer}, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::decode_instruction_type, processor::Processor, diff --git a/token/program-2022/src/extension/metadata_pointer/processor.rs b/token/program-2022/src/extension/metadata_pointer/processor.rs index d9911ad00d1..05dc07243aa 100644 --- a/token/program-2022/src/extension/metadata_pointer/processor.rs +++ b/token/program-2022/src/extension/metadata_pointer/processor.rs @@ -9,7 +9,7 @@ use { }, MetadataPointer, }, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::{decode_instruction_data, decode_instruction_type}, processor::Processor, diff --git a/token/program-2022/src/extension/mod.rs b/token/program-2022/src/extension/mod.rs index e65aebbc423..5e840959320 100644 --- a/token/program-2022/src/extension/mod.rs +++ b/token/program-2022/src/extension/mod.rs @@ -538,105 +538,28 @@ impl<'a, S: BaseState> BaseStateWithExtensions for StateWithExtensions<'a, S> } } -/// Encapsulates mutable base state data (mint or account) with possible -/// extensions -#[derive(Debug, PartialEq)] -pub struct StateWithExtensionsMut<'data, S: BaseState> { - /// Unpacked base data - pub base: S, - /// Raw base data - base_data: &'data mut [u8], - /// Writable account type - account_type: &'data mut [u8], - /// Slice of data containing all TLV data, deserialized on demand - tlv_data: &'data mut [u8], -} -impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { - /// Unpack base state, leaving the extension data as a mutable slice - /// - /// Fails if the base state is not initialized. - pub fn unpack(input: &'data mut [u8]) -> Result { - check_min_len_and_not_multisig(input, S::LEN)?; - let (base_data, rest) = input.split_at_mut(S::LEN); - let base = S::unpack(base_data)?; - if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::(rest)? { - // type_and_tlv_indices() checks that returned indexes are within range - let account_type = AccountType::try_from(rest[account_type_index]) - .map_err(|_| ProgramError::InvalidAccountData)?; - check_account_type::(account_type)?; - let (account_type, tlv_data) = rest.split_at_mut(tlv_start_index); - Ok(Self { - base, - base_data, - account_type: &mut account_type[account_type_index..tlv_start_index], - tlv_data, - }) - } else { - Ok(Self { - base, - base_data, - account_type: &mut [], - tlv_data: &mut [], - }) - } - } +/// Trait for mutable base state with extension +pub trait BaseStateWithExtensionsMut: BaseStateWithExtensions { + /// Get the underlying TLV data as mutable + fn get_tlv_data_mut(&mut self) -> &mut [u8]; - /// Unpack an uninitialized base state, leaving the extension data as a - /// mutable slice - /// - /// Fails if the base state has already been initialized. - pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result { - check_min_len_and_not_multisig(input, S::LEN)?; - let (base_data, rest) = input.split_at_mut(S::LEN); - let base = S::unpack_unchecked(base_data)?; - if base.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } - if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::(rest)? { - // type_and_tlv_indices() checks that returned indexes are within range - let account_type = AccountType::try_from(rest[account_type_index]) - .map_err(|_| ProgramError::InvalidAccountData)?; - if account_type != AccountType::Uninitialized { - return Err(ProgramError::InvalidAccountData); - } - let (account_type, tlv_data) = rest.split_at_mut(tlv_start_index); - let state = Self { - base, - base_data, - account_type: &mut account_type[account_type_index..tlv_start_index], - tlv_data, - }; - if let Some(extension_type) = state.get_first_extension_type()? { - let account_type = extension_type.get_account_type(); - if account_type != S::ACCOUNT_TYPE { - return Err(TokenError::ExtensionBaseMismatch.into()); - } - } - Ok(state) - } else { - Ok(Self { - base, - base_data, - account_type: &mut [], - tlv_data: &mut [], - }) - } - } + /// Get the underlying account type as mutable + fn get_account_type_mut(&mut self) -> &mut [u8]; /// Unpack a portion of the TLV data as the base mutable bytes - pub fn get_extension_bytes_mut(&mut self) -> Result<&mut [u8], ProgramError> { - get_extension_bytes_mut::(self.tlv_data) + fn get_extension_bytes_mut(&mut self) -> Result<&mut [u8], ProgramError> { + get_extension_bytes_mut::(self.get_tlv_data_mut()) } /// Unpack a portion of the TLV data as the desired type that allows /// modifying the type - pub fn get_extension_mut(&mut self) -> Result<&mut V, ProgramError> { + fn get_extension_mut(&mut self) -> Result<&mut V, ProgramError> { pod_from_bytes_mut::(self.get_extension_bytes_mut::()?) } /// Packs a variable-length extension into its appropriate data segment. /// Fails if space hasn't already been allocated for the given extension - pub fn pack_variable_len_extension( + fn pack_variable_len_extension( &mut self, extension: &V, ) -> Result<(), ProgramError> { @@ -646,17 +569,12 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { extension.pack_into_slice(data) } - /// Packs base state data into the base data portion - pub fn pack_base(&mut self) { - S::pack_into_slice(&self.base, self.base_data); - } - /// Packs the default extension data into an open slot if not already found /// in the data buffer. If extension is already found in the buffer, it /// overwrites the existing extension with the default state if /// `overwrite` is set. If extension found, but `overwrite` is not set, /// it returns error. - pub fn init_extension( + fn init_extension( &mut self, overwrite: bool, ) -> Result<&mut V, ProgramError> { @@ -672,7 +590,7 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { /// /// Returns an error if the extension is not present, or if there is not /// enough space in the buffer. - pub fn realloc_variable_len_extension( + fn realloc_variable_len_extension( &mut self, new_extension: &V, ) -> Result<(), ProgramError> { @@ -693,16 +611,16 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { &mut self, length: usize, ) -> Result<&mut [u8], ProgramError> { + let tlv_data = self.get_tlv_data_mut(); let TlvIndices { type_start: _, length_start, value_start, - } = get_extension_indices::(self.tlv_data, false)?; - let tlv_len = get_tlv_data_info(self.tlv_data).map(|x| x.used_len)?; - let data_len = self.tlv_data.len(); + } = get_extension_indices::(tlv_data, false)?; + let tlv_len = get_tlv_data_info(tlv_data).map(|x| x.used_len)?; + let data_len = tlv_data.len(); - let length_ref = - pod_from_bytes_mut::(&mut self.tlv_data[length_start..value_start])?; + let length_ref = pod_from_bytes_mut::(&mut tlv_data[length_start..value_start])?; let old_length = usize::from(*length_ref); // Length check to avoid a panic later in `copy_within` @@ -719,22 +637,21 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { let old_value_end = value_start.saturating_add(old_length); let new_value_end = value_start.saturating_add(length); - self.tlv_data - .copy_within(old_value_end..tlv_len, new_value_end); + tlv_data.copy_within(old_value_end..tlv_len, new_value_end); match old_length.cmp(&length) { Ordering::Greater => { // realloc to smaller, zero out the end let new_tlv_len = tlv_len.saturating_sub(old_length.saturating_sub(length)); - self.tlv_data[new_tlv_len..tlv_len].fill(0); + tlv_data[new_tlv_len..tlv_len].fill(0); } Ordering::Less => { // realloc to bigger, zero out the new bytes - self.tlv_data[old_value_end..new_value_end].fill(0); + tlv_data[old_value_end..new_value_end].fill(0); } Ordering::Equal => {} // nothing needed! } - Ok(&mut self.tlv_data[value_start..new_value_end]) + Ok(&mut tlv_data[value_start..new_value_end]) } /// Allocate the given number of bytes for the given variable-length @@ -742,7 +659,7 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { /// /// This can only be used for variable-sized types, such as `String` or /// `Vec`. `Pod` types must use `init_extension` - pub fn init_variable_len_extension( + fn init_variable_len_extension( &mut self, extension: &V, overwrite: bool, @@ -751,6 +668,7 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { extension.pack_into_slice(data) } + /// Allocate some space for the extension in the TLV data fn alloc( &mut self, length: usize, @@ -759,25 +677,26 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { if V::TYPE.get_account_type() != S::ACCOUNT_TYPE { return Err(ProgramError::InvalidAccountData); } + let tlv_data = self.get_tlv_data_mut(); let TlvIndices { type_start, length_start, value_start, - } = get_extension_indices::(self.tlv_data, true)?; + } = get_extension_indices::(tlv_data, true)?; - if self.tlv_data[type_start..].len() < add_type_and_length_to_len(length) { + if tlv_data[type_start..].len() < add_type_and_length_to_len(length) { return Err(ProgramError::InvalidAccountData); } - let extension_type = ExtensionType::try_from(&self.tlv_data[type_start..length_start])?; + let extension_type = ExtensionType::try_from(&tlv_data[type_start..length_start])?; if extension_type == ExtensionType::Uninitialized || overwrite { // write extension type let extension_type_array: [u8; 2] = V::TYPE.into(); - let extension_type_ref = &mut self.tlv_data[type_start..length_start]; + let extension_type_ref = &mut tlv_data[type_start..length_start]; extension_type_ref.copy_from_slice(&extension_type_array); // write length let length_ref = - pod_from_bytes_mut::(&mut self.tlv_data[length_start..value_start])?; + pod_from_bytes_mut::(&mut tlv_data[length_start..value_start])?; // check that the length is the same if we're doing an alloc // with overwrite, otherwise a realloc should be done @@ -788,7 +707,7 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { *length_ref = Length::try_from(length)?; let value_end = value_start.saturating_add(length); - Ok(&mut self.tlv_data[value_start..value_end]) + Ok(&mut tlv_data[value_start..value_end]) } else { // extension is already initialized, but no overwrite permission Err(TokenError::ExtensionAlreadyInitialized.into()) @@ -801,7 +720,7 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { /// already found in the data buffer, otherwise overwrites the /// existing extension with the default state. For all other ExtensionTypes, /// this is a no-op. - pub fn init_account_extension_from_type( + fn init_account_extension_from_type( &mut self, extension_type: ExtensionType, ) -> Result<(), ProgramError> { @@ -836,24 +755,137 @@ impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { /// state initialization /// Noops if there is no room for an extension in the account, needed for /// pure base mints / accounts. - pub fn init_account_type(&mut self) -> Result<(), ProgramError> { - if !self.account_type.is_empty() { - if let Some(extension_type) = self.get_first_extension_type()? { + fn init_account_type(&mut self) -> Result<(), ProgramError> { + let first_extension_type = self.get_first_extension_type()?; + let account_type = self.get_account_type_mut(); + if !account_type.is_empty() { + if let Some(extension_type) = first_extension_type { let account_type = extension_type.get_account_type(); if account_type != S::ACCOUNT_TYPE { return Err(TokenError::ExtensionBaseMismatch.into()); } } - self.account_type[0] = S::ACCOUNT_TYPE.into(); + account_type[0] = S::ACCOUNT_TYPE.into(); } Ok(()) } } + +/// Encapsulates mutable base state data (mint or account) with possible +/// extensions +#[derive(Debug, PartialEq)] +pub struct StateWithExtensionsMut<'data, S: BaseState> { + /// Unpacked base data + pub base: S, + /// Raw base data + base_data: &'data mut [u8], + /// Writable account type + account_type: &'data mut [u8], + /// Slice of data containing all TLV data, deserialized on demand + tlv_data: &'data mut [u8], +} +impl<'data, S: BaseState> StateWithExtensionsMut<'data, S> { + /// Unpack base state, leaving the extension data as a mutable slice + /// + /// Fails if the base state is not initialized. + pub fn unpack(input: &'data mut [u8]) -> Result { + check_min_len_and_not_multisig(input, S::LEN)?; + let (base_data, rest) = input.split_at_mut(S::LEN); + let base = S::unpack(base_data)?; + let (account_type, tlv_data) = unpack_type_and_tlv_data::(rest)?; + Ok(Self { + base, + base_data, + account_type, + tlv_data, + }) + } + + /// Unpack an uninitialized base state, leaving the extension data as a + /// mutable slice + /// + /// Fails if the base state has already been initialized. + pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result { + check_min_len_and_not_multisig(input, S::LEN)?; + let (base_data, rest) = input.split_at_mut(S::LEN); + let base = S::unpack_unchecked(base_data)?; + if base.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + let (account_type, tlv_data) = unpack_uninitialized_type_and_tlv_data::(rest)?; + let state = Self { + base, + base_data, + account_type, + tlv_data, + }; + if let Some(extension_type) = state.get_first_extension_type()? { + let account_type = extension_type.get_account_type(); + if account_type != S::ACCOUNT_TYPE { + return Err(TokenError::ExtensionBaseMismatch.into()); + } + } + Ok(state) + } + + /// Packs base state data into the base data portion + pub fn pack_base(&mut self) { + S::pack_into_slice(&self.base, self.base_data); + } +} impl<'a, S: BaseState> BaseStateWithExtensions for StateWithExtensionsMut<'a, S> { fn get_tlv_data(&self) -> &[u8] { self.tlv_data } } +impl<'a, S: BaseState> BaseStateWithExtensionsMut for StateWithExtensionsMut<'a, S> { + fn get_tlv_data_mut(&mut self) -> &mut [u8] { + self.tlv_data + } + fn get_account_type_mut(&mut self) -> &mut [u8] { + self.account_type + } +} + +fn unpack_type_and_tlv_data_with_check< + S: BaseState, + F: Fn(AccountType) -> Result<(), ProgramError>, +>( + rest: &mut [u8], + check_fn: F, +) -> Result<(&mut [u8], &mut [u8]), ProgramError> { + if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::(rest)? { + // type_and_tlv_indices() checks that returned indexes are within range + let account_type = AccountType::try_from(rest[account_type_index]) + .map_err(|_| ProgramError::InvalidAccountData)?; + check_fn(account_type)?; + let (account_type, tlv_data) = rest.split_at_mut(tlv_start_index); + Ok(( + &mut account_type[account_type_index..tlv_start_index], + tlv_data, + )) + } else { + Ok((&mut [], &mut [])) + } +} + +fn unpack_type_and_tlv_data( + rest: &mut [u8], +) -> Result<(&mut [u8], &mut [u8]), ProgramError> { + unpack_type_and_tlv_data_with_check::(rest, check_account_type::) +} + +fn unpack_uninitialized_type_and_tlv_data( + rest: &mut [u8], +) -> Result<(&mut [u8], &mut [u8]), ProgramError> { + unpack_type_and_tlv_data_with_check::(rest, |account_type| { + if account_type != AccountType::Uninitialized { + Err(ProgramError::InvalidAccountData) + } else { + Ok(()) + } + }) +} /// If AccountType is uninitialized, set it to the BaseState's ACCOUNT_TYPE; /// if AccountType is already set, check is set correctly for BaseState diff --git a/token/program-2022/src/extension/token_group/processor.rs b/token/program-2022/src/extension/token_group/processor.rs index 06016972833..aaad90559ca 100644 --- a/token/program-2022/src/extension/token_group/processor.rs +++ b/token/program-2022/src/extension/token_group/processor.rs @@ -6,8 +6,8 @@ use { error::TokenError, extension::{ alloc_and_serialize, group_member_pointer::GroupMemberPointer, - group_pointer::GroupPointer, BaseStateWithExtensions, StateWithExtensions, - StateWithExtensionsMut, + group_pointer::GroupPointer, BaseStateWithExtensions, BaseStateWithExtensionsMut, + StateWithExtensions, StateWithExtensionsMut, }, state::Mint, }, diff --git a/token/program-2022/src/extension/transfer_fee/processor.rs b/token/program-2022/src/extension/transfer_fee/processor.rs index ce4e1d1731b..a5cbc5d01b4 100644 --- a/token/program-2022/src/extension/transfer_fee/processor.rs +++ b/token/program-2022/src/extension/transfer_fee/processor.rs @@ -7,7 +7,8 @@ use { instruction::TransferFeeInstruction, TransferFee, TransferFeeAmount, TransferFeeConfig, MAX_FEE_BASIS_POINTS, }, - BaseStateWithExtensions, StateWithExtensions, StateWithExtensionsMut, + BaseStateWithExtensions, BaseStateWithExtensionsMut, StateWithExtensions, + StateWithExtensionsMut, }, processor::Processor, state::{Account, Mint}, diff --git a/token/program-2022/src/extension/transfer_hook/mod.rs b/token/program-2022/src/extension/transfer_hook/mod.rs index 518aa207cd8..9d391d5944f 100644 --- a/token/program-2022/src/extension/transfer_hook/mod.rs +++ b/token/program-2022/src/extension/transfer_hook/mod.rs @@ -3,7 +3,8 @@ use serde::{Deserialize, Serialize}; use { crate::{ extension::{ - BaseState, BaseStateWithExtensions, Extension, ExtensionType, StateWithExtensionsMut, + BaseState, BaseStateWithExtensions, BaseStateWithExtensionsMut, Extension, + ExtensionType, StateWithExtensionsMut, }, state::Account, }, diff --git a/token/program-2022/src/extension/transfer_hook/processor.rs b/token/program-2022/src/extension/transfer_hook/processor.rs index 41c41bcd736..6a672dae43e 100644 --- a/token/program-2022/src/extension/transfer_hook/processor.rs +++ b/token/program-2022/src/extension/transfer_hook/processor.rs @@ -9,7 +9,7 @@ use { }, TransferHook, }, - StateWithExtensionsMut, + BaseStateWithExtensionsMut, StateWithExtensionsMut, }, instruction::{decode_instruction_data, decode_instruction_type}, processor::Processor, diff --git a/token/program-2022/src/offchain.rs b/token/program-2022/src/offchain.rs index ae4edcc6d61..800f3dd2b31 100644 --- a/token/program-2022/src/offchain.rs +++ b/token/program-2022/src/offchain.rs @@ -141,7 +141,10 @@ where mod tests { use { super::*, - crate::extension::{transfer_hook::TransferHook, ExtensionType, StateWithExtensionsMut}, + crate::extension::{ + transfer_hook::TransferHook, BaseStateWithExtensionsMut, ExtensionType, + StateWithExtensionsMut, + }, solana_program::{instruction::AccountMeta, program_option::COption}, solana_program_test::tokio, spl_pod::optional_keys::OptionalNonZeroPubkey, diff --git a/token/program-2022/src/processor.rs b/token/program-2022/src/processor.rs index 8b5b5c92bb7..30334ed1830 100644 --- a/token/program-2022/src/processor.rs +++ b/token/program-2022/src/processor.rs @@ -23,8 +23,8 @@ use { reallocate, token_group, token_metadata, transfer_fee::{self, TransferFeeAmount, TransferFeeConfig}, transfer_hook::{self, TransferHook, TransferHookAccount}, - AccountType, BaseStateWithExtensions, ExtensionType, StateWithExtensions, - StateWithExtensionsMut, + AccountType, BaseStateWithExtensions, BaseStateWithExtensionsMut, ExtensionType, + StateWithExtensions, StateWithExtensionsMut, }, instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, native_mint, diff --git a/token/transfer-hook/example/tests/functional.rs b/token/transfer-hook/example/tests/functional.rs index 4e078c1fde0..82a59379bd5 100644 --- a/token/transfer-hook/example/tests/functional.rs +++ b/token/transfer-hook/example/tests/functional.rs @@ -22,7 +22,10 @@ use { state::ExtraAccountMetaList, }, spl_token_2022::{ - extension::{transfer_hook::TransferHookAccount, ExtensionType, StateWithExtensionsMut}, + extension::{ + transfer_hook::TransferHookAccount, BaseStateWithExtensionsMut, ExtensionType, + StateWithExtensionsMut, + }, state::{Account, AccountState, Mint}, }, spl_transfer_hook_interface::{