use {
crate::helpers::{
create_associated_token_account, create_unwrapped_mint, execute_create_mint,
setup_test_env, TOKEN_WRAP_CLI_BIN,
},
serial_test::serial,
solana_keypair::Keypair,
solana_signer::Signer,
solana_system_interface::instruction::create_account,
solana_transaction::Transaction,
spl_token_2022::{
extension::{transfer_fee::instruction::initialize_transfer_fee_config, ExtensionType},
instruction::{initialize_mint2, initialize_mint_close_authority},
pod::PodMint,
},
spl_token_wrap::{get_wrapped_mint_address, get_wrapped_mint_authority},
std::process::Command,
};
mod helpers;
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_only_token_2022_allowed() {
let env = setup_test_env().await;
let unwrapped_token_program = spl_token::id();
let wrapped_token_program = spl_token_2022::id();
let unwrapped_mint = create_unwrapped_mint(&env, &unwrapped_token_program).await;
let output = Command::new(TOKEN_WRAP_CLI_BIN)
.args(vec![
"close-stuck-escrow".to_string(),
"-C".to_string(),
env.config_file_path.clone(),
unwrapped_mint.to_string(),
env.payer.pubkey().to_string(),
wrapped_token_program.to_string(),
])
.output()
.unwrap();
assert!(!output.status.success());
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(stderr.contains("CloseStuckEscrow only works with spl-token-2022 unwrapped mints"));
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_mint_close_stuck_escrow_fails() {
let env = setup_test_env().await;
let unwrapped_token_program = spl_token_2022::id();
let wrapped_token_program = spl_token_2022::id();
let unwrapped_mint = create_unwrapped_mint(&env, &unwrapped_token_program).await;
execute_create_mint(&env, &unwrapped_mint, &wrapped_token_program).await;
let wrapped_mint = get_wrapped_mint_address(&unwrapped_mint, &wrapped_token_program);
let wrapped_mint_authority = get_wrapped_mint_authority(&wrapped_mint);
create_associated_token_account(
&env,
&unwrapped_token_program,
&unwrapped_mint,
&wrapped_mint_authority,
)
.await;
let output = Command::new(TOKEN_WRAP_CLI_BIN)
.args(vec![
"close-stuck-escrow".to_string(),
"-C".to_string(),
env.config_file_path.clone(),
unwrapped_mint.to_string(),
env.payer.pubkey().to_string(),
wrapped_token_program.to_string(),
])
.output()
.unwrap();
assert!(!output.status.success());
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_successful_close() {
let env = setup_test_env().await;
let unwrapped_token_program = spl_token_2022::id();
let wrapped_token_program = spl_token_2022::id();
let close_authority = env.payer.pubkey();
let unwrapped_mint_keypair = Keypair::new();
let unwrapped_mint = unwrapped_mint_keypair.pubkey();
let extensions = vec![ExtensionType::MintCloseAuthority];
let space = ExtensionType::try_calculate_account_len::<PodMint>(&extensions).unwrap();
let rent = env
.rpc_client
.get_minimum_balance_for_rent_exemption(space)
.await
.unwrap();
let blockhash = env.rpc_client.get_latest_blockhash().await.unwrap();
let create_account_ix = create_account(
&env.payer.pubkey(),
&unwrapped_mint,
rent,
space as u64,
&unwrapped_token_program,
);
let init_close_authority_ix = initialize_mint_close_authority(
&unwrapped_token_program,
&unwrapped_mint,
Some(&close_authority),
)
.unwrap();
let init_mint_ix = initialize_mint2(
&unwrapped_token_program,
&unwrapped_mint,
&env.payer.pubkey(),
None,
0,
)
.unwrap();
let tx = Transaction::new_signed_with_payer(
&[create_account_ix, init_close_authority_ix, init_mint_ix],
Some(&env.payer.pubkey()),
&[&env.payer, &unwrapped_mint_keypair],
blockhash,
);
env.rpc_client
.send_and_confirm_transaction(&tx)
.await
.unwrap();
execute_create_mint(&env, &unwrapped_mint, &wrapped_token_program).await;
let wrapped_mint = get_wrapped_mint_address(&unwrapped_mint, &wrapped_token_program);
let wrapped_mint_authority = get_wrapped_mint_authority(&wrapped_mint);
let escrow_address = create_associated_token_account(
&env,
&unwrapped_token_program,
&unwrapped_mint,
&wrapped_mint_authority,
)
.await;
let blockhash = env.rpc_client.get_latest_blockhash().await.unwrap();
let close_ix = spl_token_2022::instruction::close_account(
&unwrapped_token_program,
&unwrapped_mint,
&env.payer.pubkey(),
&env.payer.pubkey(),
&[],
)
.unwrap();
let tx = Transaction::new_signed_with_payer(
&[close_ix],
Some(&env.payer.pubkey()),
&[&env.payer],
blockhash,
);
env.rpc_client
.send_and_confirm_transaction(&tx)
.await
.unwrap();
let mint_account = env.rpc_client.get_account(&unwrapped_mint).await;
assert!(mint_account.is_err());
let extensions = vec![ExtensionType::TransferFeeConfig];
let space = ExtensionType::try_calculate_account_len::<PodMint>(&extensions).unwrap();
let rent = env
.rpc_client
.get_minimum_balance_for_rent_exemption(space)
.await
.unwrap();
let blockhash = env.rpc_client.get_latest_blockhash().await.unwrap();
let create_account_ix = create_account(
&env.payer.pubkey(),
&unwrapped_mint,
rent,
space as u64,
&unwrapped_token_program,
);
let init_mint_ix = initialize_mint2(
&unwrapped_token_program,
&unwrapped_mint,
&env.payer.pubkey(),
None,
0,
)
.unwrap();
let init_transfer_fee_ix = initialize_transfer_fee_config(
&unwrapped_token_program,
&unwrapped_mint,
Some(&env.payer.pubkey()),
Some(&env.payer.pubkey()),
100,
1_000,
)
.unwrap();
let tx = Transaction::new_signed_with_payer(
&[create_account_ix, init_transfer_fee_ix, init_mint_ix],
Some(&env.payer.pubkey()),
&[&env.payer, &unwrapped_mint_keypair],
blockhash,
);
env.rpc_client
.send_and_confirm_transaction(&tx)
.await
.unwrap();
let output = Command::new(TOKEN_WRAP_CLI_BIN)
.args([
"close-stuck-escrow",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&env.payer.pubkey().to_string(),
&wrapped_token_program.to_string(),
])
.output()
.unwrap();
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
panic!(
"close-stuck-escrow failed with status: {}\nStdout: {}\nStderr:
{}",
output.status, stdout, stderr
);
}
let escrow_account_after_close = env.rpc_client.get_account(&escrow_address).await;
assert!(escrow_account_after_close.is_err());
}