use {
crate::helpers::{create_unwrapped_mint, setup_test_env, TestEnv, TOKEN_WRAP_CLI_BIN},
serde_json::Value,
serial_test::serial,
solana_keypair::{write_keypair_file, Keypair},
solana_program_pack::IsInitialized,
solana_pubkey::Pubkey,
solana_signer::Signer,
solana_transaction::Transaction,
spl_token::{self},
spl_token_2022::{
extension::PodStateWithExtensions,
pod::PodAccount,
{self},
},
spl_token_wrap::{get_wrapped_mint_address, get_wrapped_mint_authority},
std::{process::Command, str::FromStr},
tempfile::NamedTempFile,
};
mod helpers;
async fn assert_escrow_creation(
env: &TestEnv,
cli_output: &Value,
expected_owner_pda: &Pubkey,
unwrapped_mint: &Pubkey,
expected_token_program_id: &Pubkey,
) {
let escrow_account_address_str = cli_output["escrowAccountAddress"].as_str().unwrap();
let escrow_account_address = Pubkey::from_str(escrow_account_address_str).unwrap();
let cli_reported_owner_pda_str = cli_output["escrowAccountOwner"].as_str().unwrap();
let cli_reported_owner_pda = Pubkey::from_str(cli_reported_owner_pda_str).unwrap();
let cli_reported_token_program_str = cli_output["unwrappedTokenProgramId"].as_str().unwrap();
let cli_reported_token_program_id = Pubkey::from_str(cli_reported_token_program_str).unwrap();
let escrow_account = env
.rpc_client
.get_account(&escrow_account_address)
.await
.unwrap();
assert_eq!(cli_reported_token_program_id, *expected_token_program_id);
assert_eq!(escrow_account.owner, *expected_token_program_id);
assert_eq!(cli_reported_owner_pda, *expected_owner_pda);
let account_state = PodStateWithExtensions::<PodAccount>::unpack(&escrow_account.data).unwrap();
assert!(account_state.base.is_initialized());
assert_eq!(account_state.base.mint, *unwrapped_mint);
assert_eq!(account_state.base.owner, *expected_owner_pda);
assert_eq!(account_state.base.amount, 0.into());
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_ata_escrow_account_for_spl_token_mint() {
let env = setup_test_env().await;
let unwrapped_token_program_id = spl_token::id();
let wrapped_token_program_id = spl_token_2022::id();
let unwrapped_mint = create_unwrapped_mint(&env, &unwrapped_token_program_id).await;
let wrapped_mint_address = get_wrapped_mint_address(&unwrapped_mint, &wrapped_token_program_id);
let expected_owner_pda = get_wrapped_mint_authority(&wrapped_mint_address);
let mut command = Command::new(TOKEN_WRAP_CLI_BIN);
let output = command
.args([
"create-escrow-account",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&wrapped_token_program_id.to_string(),
"--output",
"json",
])
.output()
.unwrap();
assert!(output.status.success());
let output_str = String::from_utf8(output.stdout).unwrap();
let json_result: Value = serde_json::from_str(&output_str).unwrap();
assert_escrow_creation(
&env,
&json_result,
&expected_owner_pda,
&unwrapped_mint,
&unwrapped_token_program_id,
)
.await;
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_ata_escrow_account_for_token2022_mint() {
let env = setup_test_env().await;
let unwrapped_token_program_id = spl_token_2022::id();
let wrapped_token_program_id = spl_token::id();
let unwrapped_mint = create_unwrapped_mint(&env, &unwrapped_token_program_id).await;
let wrapped_mint_address = get_wrapped_mint_address(&unwrapped_mint, &wrapped_token_program_id);
let expected_owner_pda = get_wrapped_mint_authority(&wrapped_mint_address);
let mut command = Command::new(TOKEN_WRAP_CLI_BIN);
let output = command
.args([
"create-escrow-account",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&wrapped_token_program_id.to_string(),
"--output",
"json",
])
.output()
.unwrap();
assert!(output.status.success());
let output_str = String::from_utf8(output.stdout).unwrap();
let json_result: Value = serde_json::from_str(&output_str).unwrap();
assert_escrow_creation(
&env,
&json_result,
&expected_owner_pda,
&unwrapped_mint,
&unwrapped_token_program_id,
)
.await;
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_escrow_account_with_signer() {
let env = setup_test_env().await;
let unwrapped_token_program_id = spl_token::id();
let wrapped_token_program_id = spl_token_2022::id();
let unwrapped_mint = create_unwrapped_mint(&env, &unwrapped_token_program_id).await;
let escrow_keypair = Keypair::new();
let escrow_keypair_file = NamedTempFile::new().unwrap();
write_keypair_file(&escrow_keypair, &escrow_keypair_file).unwrap();
let mut command = Command::new(TOKEN_WRAP_CLI_BIN);
let output = command
.args([
"create-escrow-account",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&wrapped_token_program_id.to_string(),
"--output",
"json",
])
.output()
.unwrap();
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
panic!(
"Creation with signer failed with status: {}\nStdout: {}\nStderr: {}",
output.status, stdout, stderr
);
}
let output_str = String::from_utf8(output.stdout).unwrap();
let json_result: Value = serde_json::from_str(&output_str).unwrap();
let wrapped_mint_address = get_wrapped_mint_address(&unwrapped_mint, &wrapped_token_program_id);
let expected_owner_pda = get_wrapped_mint_authority(&wrapped_mint_address);
assert_escrow_creation(
&env,
&json_result,
&expected_owner_pda,
&unwrapped_mint,
&unwrapped_token_program_id,
)
.await;
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_escrow_account_signer_idempotent() {
let env = setup_test_env().await;
let unwrapped_token_program_id = spl_token::id();
let wrapped_token_program_id = spl_token_2022::id();
let unwrapped_mint = create_unwrapped_mint(&env, &unwrapped_token_program_id).await;
let args = [
"create-escrow-account",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&wrapped_token_program_id.to_string(),
"--idempotent",
];
let mut command_a = Command::new(TOKEN_WRAP_CLI_BIN);
let status_a = command_a.args(args).status().unwrap();
assert!(status_a.success());
let mut command_b = Command::new(TOKEN_WRAP_CLI_BIN);
let status_b = command_b.args(args).status().unwrap();
assert!(status_b.success());
let mut command_c = Command::new(TOKEN_WRAP_CLI_BIN);
let output = command_c
.args([
"create-escrow-account",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&wrapped_token_program_id.to_string(),
])
.output()
.unwrap();
assert!(!output.status.success());
let stderr = String::from_utf8(output.stderr).unwrap();
let derived_escrow_address = spl_token_wrap::get_escrow_address(
&unwrapped_mint,
&unwrapped_token_program_id,
&wrapped_token_program_id,
);
assert!(stderr
.contains(format!("Escrow account {} already exists", derived_escrow_address).as_str()));
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_escrow_account_ata_idempotent() {
let env = setup_test_env().await;
let unwrapped_token_program_id = spl_token::id();
let wrapped_token_program_id = spl_token_2022::id();
let unwrapped_mint = create_unwrapped_mint(&env, &unwrapped_token_program_id).await;
let args = [
"create-escrow-account",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&wrapped_token_program_id.to_string(),
"--idempotent",
];
let mut command_a = Command::new(TOKEN_WRAP_CLI_BIN);
let status_a = command_a.args(args).status().unwrap();
assert!(status_a.success());
let mut command_b = Command::new(TOKEN_WRAP_CLI_BIN);
let status_b = command_b.args(args).status().unwrap();
assert!(status_b.success());
let mut command_c = Command::new(TOKEN_WRAP_CLI_BIN);
let output_c = command_c
.args([
"create-escrow-account",
"-C",
&env.config_file_path,
&unwrapped_mint.to_string(),
&wrapped_token_program_id.to_string(),
])
.output()
.unwrap();
assert!(!output_c.status.success());
let stderr_c = String::from_utf8(output_c.stderr).unwrap();
assert!(stderr_c.contains("already exists"));
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_escrow_account_with_wrong_mint_owner() {
let env = setup_test_env().await;
let keypair = Keypair::new();
let wrong_owner = Pubkey::new_unique();
create_account(&env, &keypair, &wrong_owner).await;
let mut command = Command::new(TOKEN_WRAP_CLI_BIN);
let output = command
.args([
"create-escrow-account",
"-C",
&env.config_file_path,
&keypair.pubkey().to_string(),
&spl_token_2022::id().to_string(),
])
.output()
.unwrap();
assert!(!output.status.success());
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(stderr.contains("is not owned by a token program"));
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn test_create_escrow_account_with_wrong_account_type() {
let env = setup_test_env().await;
let keypair = Keypair::new();
create_account(&env, &keypair, &spl_token_2022::id()).await;
let mut command = Command::new(TOKEN_WRAP_CLI_BIN);
let output = command
.args([
"create-escrow-account",
"-C",
&env.config_file_path,
&keypair.pubkey().to_string(),
&spl_token_2022::id().to_string(),
])
.output()
.unwrap();
assert!(!output.status.success());
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(stderr.contains("Failed to unpack as spl token mint:"));
}
async fn create_account(env: &TestEnv, key_pair: &Keypair, owner: &Pubkey) {
let tx = Transaction::new_signed_with_payer(
&[solana_system_interface::instruction::create_account(
&env.payer.pubkey(),
&key_pair.pubkey(),
env.rpc_client
.get_minimum_balance_for_rent_exemption(100)
.await
.unwrap(),
100,
owner,
)],
Some(&env.payer.pubkey()),
&[&env.payer, key_pair],
env.rpc_client.get_latest_blockhash().await.unwrap(),
);
env.rpc_client
.send_and_confirm_transaction(&tx)
.await
.unwrap();
}