Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@ pub fn process_close_stuck_escrow(accounts: &[AccountInfo]) -> ProgramResult {
ExtensionType::get_required_init_account_extensions(&mint_extensions);

// ATAs always have the ImmutableOwner extension
required_account_extensions.push(ExtensionType::ImmutableOwner);
if !required_account_extensions.contains(&ExtensionType::ImmutableOwner) {
required_account_extensions.push(ExtensionType::ImmutableOwner);
}

// If the token account already shares the same extensions as the mint,
// it does not need to be re-created
Expand Down
11 changes: 11 additions & 0 deletions program/tests/helpers/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use {
confidential_transfer::ConfidentialTransferMint,
immutable_owner::ImmutableOwner,
mint_close_authority::MintCloseAuthority,
non_transferable::{NonTransferable, NonTransferableAccount},
transfer_fee::{TransferFee, TransferFeeAmount, TransferFeeConfig},
transfer_hook::{TransferHook, TransferHookAccount},
BaseStateWithExtensionsMut, ExtensionType, PodStateWithExtensionsMut,
Expand All @@ -20,6 +21,7 @@ pub enum MintExtension {
TransferHook,
TransferFeeConfig,
MintCloseAuthority(Pubkey),
NonTransferable,
}

impl MintExtension {
Expand All @@ -29,6 +31,7 @@ impl MintExtension {
MintExtension::TransferFeeConfig => ExtensionType::TransferFeeConfig,
MintExtension::MintCloseAuthority(_) => ExtensionType::MintCloseAuthority,
MintExtension::ConfidentialTransfer => ExtensionType::ConfidentialTransferMint,
MintExtension::NonTransferable => ExtensionType::NonTransferable,
}
}
}
Expand Down Expand Up @@ -79,6 +82,9 @@ pub fn init_mint_extensions(
.init_extension::<ConfidentialTransferMint>(false)
.unwrap();
}
MintExtension::NonTransferable => {
state.init_extension::<NonTransferable>(false).unwrap();
}
}
}
}
Expand All @@ -102,6 +108,11 @@ pub fn init_token_account_extensions(
ExtensionType::TransferHookAccount => {
state.init_extension::<TransferHookAccount>(true).unwrap();
}
ExtensionType::NonTransferableAccount => {
state
.init_extension::<NonTransferableAccount>(true)
.unwrap();
}
_ => unimplemented!(),
}
}
Expand Down
51 changes: 49 additions & 2 deletions program/tests/test_stuck_escrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::helpers::{
close_stuck_escrow_builder::CloseStuckEscrowBuilder,
common::{init_mollusk, KeyedAccount, TokenProgram, DEFAULT_MINT_DECIMALS},
extensions::MintExtension::{MintCloseAuthority, TransferHook},
extensions::MintExtension::{MintCloseAuthority, NonTransferable, TransferHook},
mint_builder::MintBuilder,
token_account_builder::TokenAccountBuilder,
},
Expand All @@ -22,7 +22,10 @@ use {
extension::{
transfer_fee::instruction::initialize_transfer_fee_config,
BaseStateWithExtensionsMut,
ExtensionType::{self, ImmutableOwner, TransferFeeConfig, TransferHookAccount},
ExtensionType::{
self, ImmutableOwner, NonTransferableAccount, TransferFeeConfig,
TransferHookAccount,
},
PodStateWithExtensionsMut,
},
instruction::initialize_mint2,
Expand Down Expand Up @@ -256,6 +259,50 @@ fn test_close_stuck_escrow_fails_when_in_good_state() {
.execute();
}

#[test]
fn test_fails_for_ext_requiring_immutable_owner_and_in_good_state() {
let unwrapped_mint = MintBuilder::new()
.token_program(TokenProgram::SplToken2022)
.with_extension(NonTransferable)
.build();
let wrapped_token_program = TokenProgram::SplToken2022;

let wrapped_mint = MintBuilder::new()
.token_program(wrapped_token_program)
.mint_key(get_wrapped_mint_address(
&unwrapped_mint.key,
&wrapped_token_program.id(),
))
.build();

let wrapped_mint_authority = get_wrapped_mint_authority(&wrapped_mint.key);

let escrow_address = get_escrow_address(
&unwrapped_mint.key,
&unwrapped_mint.account.owner,
&wrapped_token_program.id(),
);

let escrow_account = TokenAccountBuilder::new()
.token_program(TokenProgram::SplToken2022)
.mint(unwrapped_mint.clone())
.owner(wrapped_mint_authority)
.amount(0)
.with_extension(NonTransferableAccount)
.with_extension(ImmutableOwner)
.account_key(escrow_address)
.build();

// ImmutableOwner is required for NonTransferable ext (same as ATA). Ensures no
// issues with duplication of that requirement.
CloseStuckEscrowBuilder::default()
.unwrapped_mint(unwrapped_mint)
.wrapped_mint(wrapped_mint)
.escrow_account(escrow_account)
.check(Check::err(TokenWrapError::EscrowInGoodState.into()))
.execute();
}

#[test]
fn test_close_stuck_escrow_succeeds() {
let wrapped_token_program = TokenProgram::SplToken2022;
Expand Down