use { crate::{utils, utils::Swap}, solana_farm_client::client::FarmClient, solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair, signer::Signer}, std::{thread, time}, }; const MAX_SOL_BALANCE_TO_USE: f64 = 0.1; const INITIAL_CRANK_DELAY: u64 = 600; const CRANK_INTERVAL: u64 = 100; pub fn do_swap(client: &FarmClient, keypair: &Keypair, swap: &Swap) { let amount = if swap.amount == 0.0 { utils::get_token_or_native_balance(client, &keypair.pubkey(), swap.from_token) } else if swap.amount < 0.0 { -1.0 * swap.amount * utils::get_token_or_native_balance(client, &keypair.pubkey(), swap.from_token) } else { swap.amount }; if amount < 0.0003 { return; } println!( ">> Swap {} {} to {}", amount, swap.from_token, swap.to_token ); println!( " Done: {}", client .swap( keypair, swap.protocol .parse() .expect("Failed to parse protocol argument"), swap.from_token, swap.to_token, amount, 0.0, ) .unwrap() ); let _ = utils::get_balances( client, &keypair.pubkey(), swap.from_token, swap.to_token, "After swap", ); } pub fn do_add_liquidity( client: &FarmClient, keypair: &Keypair, vault_name: &str, max_token_a_ui_amount: f64, max_token_b_ui_amount: f64, ) -> f64 { println!( ">> Add liquidity to {}: {}, {}", vault_name, max_token_a_ui_amount, max_token_b_ui_amount ); let (token_a_str, token_b_str, vt_token_name) = client.get_vault_token_names(vault_name).unwrap(); let vt_balance = utils::get_token_or_native_balance(client, &keypair.pubkey(), &vt_token_name); println!( " Done: {}", client .add_liquidity_vault( keypair, vault_name, max_token_a_ui_amount, max_token_b_ui_amount, ) .unwrap() ); let _ = utils::get_balances( client, &keypair.pubkey(), &token_a_str, &token_b_str, "After add liquidity", ); let _ = utils::get_balance(client, &keypair.pubkey(), &vt_token_name, "VT"); let _ = utils::get_vault_stake_balance(client, vault_name); utils::get_token_or_native_balance(client, &keypair.pubkey(), &vt_token_name) - vt_balance } pub fn do_crank(client: &FarmClient, keypair: &Keypair, vault_name: &str, step: u64) { println!(">> Crank {} with step {}", vault_name, step); let initial_info = client.get_vault_info(vault_name).unwrap(); println!( " Done: {}", client.crank_vault(keypair, vault_name, step).unwrap() ); let after_crank_info = client.get_vault_info(vault_name).unwrap(); println!( " Rewards received: {}, {}", after_crank_info.tokens_a_rewards - initial_info.tokens_a_rewards, after_crank_info.tokens_b_rewards - initial_info.tokens_b_rewards ); let _ = utils::get_vault_stake_balance(client, vault_name); } pub fn do_remove_liquidity(client: &FarmClient, keypair: &Keypair, vault_name: &str, amount: f64) { println!(">> Remove liquidity from {}: {}", vault_name, amount); let (token_a_str, token_b_str, vt_token_name) = client.get_vault_token_names(vault_name).unwrap(); println!( " Done: {}", client .remove_liquidity_vault(keypair, vault_name, amount) .unwrap() ); let _ = utils::get_balances( client, &keypair.pubkey(), &token_a_str, &token_b_str, "After remove liquidity", ); let _ = utils::get_balance(client, &keypair.pubkey(), &vt_token_name, "VT"); let _ = utils::get_vault_stake_balance(client, vault_name); } pub fn cleanup(client: &FarmClient, keypair: &Keypair, vault_name: &str, cleanup_swaps: Vec) { println!("\n>>> Clean-up {}...", vault_name); let wallet = keypair.pubkey(); let (token_a_str, token_b_str, vt_token_name) = client.get_vault_token_names(vault_name).unwrap(); let vt_token_balance = utils::get_token_or_native_balance(client, &wallet, &vt_token_name); if vt_token_balance > 0.0 { do_remove_liquidity(client, keypair, vault_name, vt_token_balance); } for swap in cleanup_swaps { do_swap(client, keypair, &swap); } if token_a_str != "SOL" { let token_a_balance = utils::get_token_or_native_balance(client, &wallet, &token_a_str); if token_a_balance > 0.0 { do_swap( client, keypair, &Swap { protocol: "RDM", from_token: token_a_str.as_str(), to_token: "SOL", amount: token_a_balance, }, ); } } if token_b_str != "SOL" { let token_b_balance = utils::get_token_or_native_balance(client, &wallet, &token_b_str); if token_b_balance > 0.0 { do_swap( client, keypair, &Swap { protocol: "RDM", from_token: token_b_str.as_str(), to_token: "SOL", amount: token_b_balance, }, ); } } let _ = utils::get_vault_stake_balance(client, vault_name); } pub fn run_test(vault_name: &str, swaps: Vec, cleanup_swaps: Vec) { let (endpoint, keypair) = utils::get_endpoint_and_keypair(); let client = FarmClient::new_with_commitment(&endpoint, CommitmentConfig::confirmed()); let wallet = keypair.pubkey(); cleanup(&client, &keypair, vault_name, cleanup_swaps.clone()); println!("\n>>> Testing {}...", vault_name); let (token_a_str, token_b_str, _) = client.get_vault_token_names(vault_name).unwrap(); let (_, _) = utils::get_balances(&client, &wallet, &token_a_str, &token_b_str, "Initial"); let _ = utils::get_vault_stake_balance(&client, vault_name); //initial swaps for swap in swaps { do_swap(&client, &keypair, &swap); } let token_a_balance = if token_a_str == "SOL" { MAX_SOL_BALANCE_TO_USE.min(utils::get_token_or_native_balance( &client, &wallet, &token_a_str, )) } else { utils::get_token_or_native_balance(&client, &wallet, &token_a_str) }; let token_b_balance = if token_b_str == "SOL" { MAX_SOL_BALANCE_TO_USE.min(utils::get_token_or_native_balance( &client, &wallet, &token_b_str, )) } else { utils::get_token_or_native_balance(&client, &wallet, &token_b_str) }; // main tests let mut vt_received; if vault_name.starts_with("SBR.") { if token_a_str == "USDC" { assert!(token_a_balance > 0.0); vt_received = do_add_liquidity( &client, &keypair, vault_name, token_a_balance * 2.0 / 3.0, 0.0, ); } else { assert!(token_b_balance > 0.0); vt_received = do_add_liquidity( &client, &keypair, vault_name, 0.0, token_b_balance * 2.0 / 3.0, ); } } else { assert!(token_a_balance > 0.0 && token_b_balance > 0.0); vt_received = do_add_liquidity(&client, &keypair, vault_name, token_a_balance / 3.0, 0.0); assert!(vt_received > 0.0); vt_received += do_add_liquidity(&client, &keypair, vault_name, 0.0, token_b_balance / 3.0); } println!("Waiting {} secs for rewards...", INITIAL_CRANK_DELAY); thread::sleep(time::Duration::from_secs(INITIAL_CRANK_DELAY)); do_crank(&client, &keypair, vault_name, 1); let cranks = if vault_name.starts_with("SBR.") { 6 } else { 4 }; for step in 2..cranks { println!("Waiting {} secs before next crank...", CRANK_INTERVAL); thread::sleep(time::Duration::from_secs(CRANK_INTERVAL)); do_crank(&client, &keypair, vault_name, step); } do_remove_liquidity(&client, &keypair, vault_name, vt_received / 2.0); do_remove_liquidity(&client, &keypair, vault_name, 0.0); cleanup(&client, &keypair, vault_name, cleanup_swaps); let (_, _) = utils::get_balances(&client, &wallet, &token_a_str, &token_b_str, "Final"); let _ = utils::get_vault_stake_balance(&client, vault_name); }