diff --git a/swap/src/api.rs b/swap/src/api.rs index 144d4f39..9f38fbce 100644 --- a/swap/src/api.rs +++ b/swap/src/api.rs @@ -22,12 +22,12 @@ pub struct Config { tor_socks5_port: Option, namespace: XmrBtcNamespace, server_address: Option, - env_config: EnvConfig, + pub env_config: EnvConfig, seed: Option, debug: bool, json: bool, data_dir: PathBuf, - pub is_testnet: bool, + is_testnet: bool, } use uuid::Uuid; @@ -127,7 +127,7 @@ pub struct Context { bitcoin_wallet: Option>, monero_wallet: Option>, monero_rpc_process: Option, - swap_lock: Arc, + pub swap_lock: Arc, pub config: Config, } diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index cffc8c9e..92c898a7 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -278,13 +278,10 @@ pub mod bitcoin_address { Ok(address) } - pub fn validate(address: bitcoin::Address, is_testnet: bool) -> Result { - let expected_network = if is_testnet { - bitcoin::Network::Testnet - } else { - bitcoin::Network::Bitcoin - }; - + pub fn validate( + address: bitcoin::Address, + expected_network: bitcoin::Network, + ) -> Result { if address.network != expected_network { bail!(BitcoinAddressNetworkMismatch { expected: expected_network, @@ -294,6 +291,18 @@ pub mod bitcoin_address { Ok(address) } + + pub fn validate_is_testnet( + address: bitcoin::Address, + is_testnet: bool, + ) -> Result { + let expected_network = if is_testnet { + bitcoin::Network::Testnet + } else { + bitcoin::Network::Bitcoin + }; + return validate(address, expected_network); + } } /// Bitcoin error codes: https://github.com/bitcoin/bitcoin/blob/97d3500601c1d28642347d014a6de1e38f53ae4e/src/rpc/protocol.h#L23 diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 6218fb6f..94b49d0d 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -193,7 +193,6 @@ impl Wallet { tokio::time::sleep(Duration::from_secs(5)).await; } - }.instrument(Span::current())); }.instrument(Span::none())); Subscription { @@ -787,10 +786,10 @@ impl Client { if !self.script_history.contains_key(&script) { self.script_history.insert(script.clone(), vec![]); self.update_state(true)?; - }else { + } else { self.update_state(false)?; } - + let history = self.script_history.entry(script).or_default(); let history_of_tx = history @@ -1007,7 +1006,6 @@ mod tests { #[test] fn given_depth_0_should_meet_confirmation_target_one() { - let script = ScriptStatus::Confirmed(Confirmed { depth: 0 }); let confirmed = script.is_confirmed_with(1 as u32); diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index 242b48ce..d207ca98 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -70,9 +70,9 @@ where tor, } => { let monero_receive_address = - monero_address::validate(monero_receive_address, is_testnet)?; + monero_address::validate_is_testnet(monero_receive_address, is_testnet)?; let bitcoin_change_address = - bitcoin_address::validate(bitcoin_change_address, is_testnet)?; + bitcoin_address::validate_is_testnet(bitcoin_change_address, is_testnet)?; let request = Request::new(Method::BuyXmr { seller, @@ -150,8 +150,7 @@ where amount, address, } => { - let address = bitcoin_address::validate(address, is_testnet)?; - + let address = bitcoin_address::validate_is_testnet(address, is_testnet)?; let request = Request::new(Method::WithdrawBtc { amount, address }); let context = Context::build( @@ -538,10 +537,13 @@ mod tests { ); // since Uuid is random, copy before comparing requests - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -574,10 +576,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -771,10 +776,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -810,10 +818,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -839,10 +850,13 @@ mod tests { Request::resume(), ); - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -908,10 +922,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -945,10 +962,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -971,10 +991,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -1033,10 +1056,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; @@ -1070,10 +1096,13 @@ mod tests { _ => panic!("Couldn't parse result"), }; - if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + if let Method::BuyXmr { + ref mut swap_id, .. + } = expected_request.cmd + { *swap_id = match actual_request.cmd { - Method::BuyXmr { swap_id, .. } => { swap_id }, - _ => panic!("Not the Method we expected") + Method::BuyXmr { swap_id, .. } => swap_id, + _ => panic!("Not the Method we expected"), } }; diff --git a/swap/src/monero.rs b/swap/src/monero.rs index 1e1e5583..01059fa5 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -347,13 +347,10 @@ pub mod monero_address { }) } - pub fn validate(address: monero::Address, is_testnet: bool) -> Result { - let expected_network = if is_testnet { - monero::Network::Stagenet - } else { - monero::Network::Mainnet - }; - + pub fn validate( + address: monero::Address, + expected_network: monero::Network, + ) -> Result { if address.network != expected_network { bail!(MoneroAddressNetworkMismatch { expected: expected_network, @@ -362,6 +359,18 @@ pub mod monero_address { } Ok(address) } + + pub fn validate_is_testnet( + address: monero::Address, + is_testnet: bool, + ) -> Result { + let expected_network = if is_testnet { + monero::Network::Testnet + } else { + monero::Network::Mainnet + }; + validate(address, expected_network) + } } #[cfg(test)] diff --git a/swap/src/rpc/methods.rs b/swap/src/rpc/methods.rs index 1ebd8824..f0dad7b3 100644 --- a/swap/src/rpc/methods.rs +++ b/swap/src/rpc/methods.rs @@ -125,8 +125,10 @@ pub fn register_modules(context: Arc) -> RpcModule> { jsonrpsee_core::Error::Custom("Does not contain address".to_string()) })?) .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?; - let withdraw_address = - bitcoin_address::validate(withdraw_address, context.config.is_testnet)?; + let withdraw_address = bitcoin_address::validate( + withdraw_address, + context.config.env_config.bitcoin_network, + )?; execute_request( params_raw, @@ -153,8 +155,10 @@ pub fn register_modules(context: Arc) -> RpcModule> { ) .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?; - let bitcoin_change_address = - bitcoin_address::validate(bitcoin_change_address, context.config.is_testnet)?; + let bitcoin_change_address = bitcoin_address::validate( + bitcoin_change_address, + context.config.env_config.bitcoin_network, + )?; let monero_receive_address = monero::Address::from_str( params.get("monero_receive_address").ok_or_else(|| { @@ -165,8 +169,10 @@ pub fn register_modules(context: Arc) -> RpcModule> { ) .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?; - let monero_receive_address = - monero_address::validate(monero_receive_address, context.config.is_testnet)?; + let monero_receive_address = monero_address::validate( + monero_receive_address, + context.config.env_config.monero_network, + )?; let seller = Multiaddr::from_str(params.get("seller").ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain seller".to_string()) diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 49bdbe32..b42b37ee 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -402,7 +402,7 @@ impl StartingBalances { } } -struct BobParams { +pub struct BobParams { seed: Seed, db_path: PathBuf, bitcoin_wallet: Arc, @@ -413,6 +413,21 @@ struct BobParams { } impl BobParams { + pub fn get_concentenated_alice_address(&self) -> String { + format!( + "{}/p2p/{}", + self.alice_address.clone().to_string(), + self.alice_peer_id.clone().to_base58() + ) + } + + pub async fn get_change_receive_addresses(&self) -> (bitcoin::Address, monero::Address) { + ( + self.bitcoin_wallet.new_address().await.unwrap(), + self.monero_wallet.get_main_address(), + ) + } + pub async fn new_swap_from_db(&self, swap_id: Uuid) -> Result<(bob::Swap, cli::EventLoop)> { let (event_loop, handle) = self.new_eventloop(swap_id).await?; @@ -529,7 +544,7 @@ pub struct TestContext { alice_swap_handle: mpsc::Receiver, alice_handle: AliceApplicationHandle, - bob_params: BobParams, + pub bob_params: BobParams, bob_starting_balances: StartingBalances, bob_bitcoin_wallet: Arc, bob_monero_wallet: Arc, diff --git a/swap/tests/rpc.rs b/swap/tests/rpc.rs index d2df7c52..2cf9f0d2 100644 --- a/swap/tests/rpc.rs +++ b/swap/tests/rpc.rs @@ -7,82 +7,64 @@ use jsonrpsee_core::params::ObjectParams; use serial_test::serial; -use serde_json::{json, Value}; +use serde_json::Value; use std::collections::HashMap; -use std::future::Future; use std::net::SocketAddr; -use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; use swap::api::request::{Method, Request}; -use swap::api::{Config, Context, SwapLock}; -use swap::cli::command::{Bitcoin, Monero}; -use tempfile::tempdir; +use swap::api::Context; use tracing_subscriber::filter::LevelFilter; use crate::harness::alice_run_until::is_xmr_lock_transaction_sent; use crate::harness::bob_run_until::is_btc_locked; use crate::harness::{setup_test, SlowCancelConfig, TestContext}; use swap::asb::FixedRate; -use swap::database::open_db; -use swap::network::rendezvous::XmrBtcNamespace; use swap::protocol::{alice, bob}; use swap::tracing_ext::{capture_logs, MakeCapturingWriter}; use uuid::Uuid; -#[cfg(test)] - -// to be replaced with actual "real" testing values -// need to create some kind of swap database and bitcoin environment with some -// funds const SERVER_ADDRESS: &str = "127.0.0.1:1234"; +const SERVER_START_TIMEOUT_SECS: u64 = 50; const BITCOIN_ADDR: &str = "tb1qr3em6k3gfnyl8r7q0v7t4tlnyxzgxma3lressv"; const MONERO_ADDR: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a"; const SELLER: &str = "/ip4/127.0.0.1/tcp/9939/p2p/12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi"; const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b"; -const SERVER_START_TIMEOUT_SECS: u64 = 50; -pub async fn setup_daemon(testfn: T) -where - T: Fn(TestContext, Client, MakeCapturingWriter, Arc) -> F, - F: Future>, -{ - setup_test(SlowCancelConfig, |harness_context| async move { - let writer = capture_logs(LevelFilter::DEBUG); - let server_address: SocketAddr = SERVER_ADDRESS.parse().unwrap(); +pub async fn setup_daemon(harness_ctx: TestContext) -> (Client, MakeCapturingWriter, Arc) { + let writer = capture_logs(LevelFilter::DEBUG); + let server_address: SocketAddr = SERVER_ADDRESS.parse().unwrap(); - let request = Request::new(Method::StartDaemon { - server_address: Some(server_address), - }); + let request = Request::new(Method::StartDaemon { + server_address: Some(server_address), + }); - let context = Arc::new(harness_context.get_bob_context().await); + let context = Arc::new(harness_ctx.get_bob_context().await); - let context_clone = context.clone(); + let context_clone = context.clone(); - tokio::spawn(async move { - if let Err(err) = request.call(context_clone).await { - println!("Failed to initialize daemon for testing: {}", err); - } - }); + tokio::spawn(async move { + if let Err(err) = request.call(context_clone).await { + println!("Failed to initialize daemon for testing: {}", err); + } + }); - for _ in 0..SERVER_START_TIMEOUT_SECS { - if writer.captured().contains("Started RPC server") { - let url = format!("ws://{}", SERVER_ADDRESS); - let client = WsClientBuilder::default().build(&url).await.unwrap(); + for _ in 0..SERVER_START_TIMEOUT_SECS { + if writer.captured().contains("Started RPC server") { + let url = format!("ws://{}", SERVER_ADDRESS); + let client = WsClientBuilder::default().build(&url).await.unwrap(); - return testfn(harness_context, client, writer, context).await; - } - - tokio::time::sleep(Duration::from_secs(1)).await; + return (client, writer, context); } - panic!( - "Failed to start RPC server after {} seconds", - SERVER_START_TIMEOUT_SECS - ); - }) - .await + tokio::time::sleep(Duration::from_secs(1)).await; + } + + panic!( + "Failed to start RPC server after {} seconds", + SERVER_START_TIMEOUT_SECS + ); } fn assert_has_keys_serde(map: &serde_json::Map, keys: &[&str]) { @@ -101,7 +83,8 @@ fn assert_has_keys_hashmap(map: &HashMap, keys: &[&str]) { #[tokio::test] #[serial] pub async fn can_start_server() { - setup_daemon(|_, _, _, _| async move { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (_, _, _) = setup_daemon(harness_ctx).await; assert!(true); Ok(()) }) @@ -111,7 +94,9 @@ pub async fn can_start_server() { #[tokio::test] #[serial] pub async fn get_bitcoin_balance() { - setup_daemon(|_, client| async move { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + let response: HashMap = client .request("get_bitcoin_balance", ObjectParams::new()) .await @@ -127,7 +112,9 @@ pub async fn get_bitcoin_balance() { #[tokio::test] #[serial] pub async fn get_bitcoin_balance_with_log_reference_id() { - setup_daemon(|_, client, writer| async move { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, writer, _) = setup_daemon(harness_ctx).await; + let mut params = ObjectParams::new(); params.insert("log_reference_id", "test_ref_id").unwrap(); @@ -144,7 +131,7 @@ pub async fn get_bitcoin_balance_with_log_reference_id() { #[tokio::test] #[serial] pub async fn get_history() { - setup_daemon(|mut harness_ctx, client| async move { + setup_test(SlowCancelConfig, |mut harness_ctx| async move { // Start a swap and wait for xmr lock transaction to be published (XmrLockTransactionSent) let (bob_swap, _) = harness_ctx.bob_swap().await; let bob_swap_id = bob_swap.id; @@ -157,6 +144,8 @@ pub async fn get_history() { ) .await?; + let (client, _, _) = setup_daemon(harness_ctx).await; + let response: HashMap> = client .request("get_history", ObjectParams::new()) .await @@ -173,7 +162,7 @@ pub async fn get_history() { #[tokio::test] #[serial] pub async fn get_raw_states() { - setup_daemon(|mut harness_ctx, client| async move { + setup_test(SlowCancelConfig, |mut harness_ctx| async move { // Start a swap and wait for xmr lock transaction to be published (XmrLockTransactionSent) let (bob_swap, _) = harness_ctx.bob_swap().await; let bob_swap_id = bob_swap.id; @@ -186,6 +175,8 @@ pub async fn get_raw_states() { ) .await?; + let (client, _, _) = setup_daemon(harness_ctx).await; + let response: HashMap>> = client .request("get_raw_states", ObjectParams::new()) .await @@ -204,7 +195,7 @@ pub async fn get_raw_states() { #[tokio::test] #[serial] pub async fn get_swap_info_valid_swap_id() { - setup_daemon(|mut harness_ctx, client| async move { + setup_test(SlowCancelConfig, |mut harness_ctx| async move { // Start a swap and wait for xmr lock transaction to be published (XmrLockTransactionSent) let (bob_swap, _) = harness_ctx.bob_swap().await; let bob_swap_id = bob_swap.id; @@ -217,6 +208,8 @@ pub async fn get_swap_info_valid_swap_id() { ) .await?; + let (client, _, _) = setup_daemon(harness_ctx).await; + let mut params = ObjectParams::new(); params.insert("swap_id", bob_swap_id).unwrap(); let response: HashMap = @@ -291,7 +284,9 @@ pub async fn get_swap_info_valid_swap_id() { #[tokio::test] #[serial] pub async fn swap_endpoints_invalid_or_missing_swap_id() { - setup_daemon(|_, client| async move { + setup_test(SlowCancelConfig, |mut harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + for method in ["get_swap_info", "resume_swap", "cancel_refund_swap"].iter() { let mut params = ObjectParams::new(); params.insert("swap_id", "invalid_swap").unwrap(); @@ -318,7 +313,9 @@ pub async fn swap_endpoints_invalid_or_missing_swap_id() { #[tokio::test] pub async fn list_sellers_missing_rendezvous_point() { - setup_daemon(|_, client| async move { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + let params = ObjectParams::new(); let result: Result, _> = client.request("list_sellers", params).await; @@ -330,222 +327,332 @@ pub async fn list_sellers_missing_rendezvous_point() { .await; } -/* #[tokio::test] #[serial] pub async fn resume_swap_valid_swap_id() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params.insert("swap_id", SWAP_ID).unwrap(); - let response: Result, _> = client.request("resume_swap", params).await; - response.expect("Expected a HashMap, got an error"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let params = ObjectParams::new(); + let result: Result, _> = + client.request("list_sellers", params).await; + + result.expect_err("Expected an error when rendezvous_point is missing"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn withdraw_btc_missing_address() { - let (client, _, _) = initialize_context().await; - let params = ObjectParams::new(); - let response: Result, _> = client.request("withdraw_btc", params).await; - response.expect_err("Expected an error when withdraw_address is missing"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let params = ObjectParams::new(); + let response: Result, _> = + client.request("withdraw_btc", params).await; + response.expect_err("Expected an error when withdraw_address is missing"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn withdraw_btc_invalid_address() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params.insert("address", "invalid_address").unwrap(); - let response: Result, _> = client.request("withdraw_btc", params).await; - response.expect_err("Expected an error when withdraw_address is malformed"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params.insert("address", "invalid_address").unwrap(); + let response: Result, _> = + client.request("withdraw_btc", params).await; + response.expect_err("Expected an error when withdraw_address is malformed"); + + Ok(()) + }) + .await } #[tokio::test] #[serial] pub async fn withdraw_btc_zero_amount() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params.insert("address", BITCOIN_ADDR).unwrap(); - params.insert("amount", "0").unwrap(); - let response: Result, _> = client.request("withdraw_btc", params).await; - response.expect_err("Expected an error when amount is 0"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params.insert("address", BITCOIN_ADDR).unwrap(); + params.insert("amount", "0").unwrap(); + let response: Result, _> = + client.request("withdraw_btc", params).await; + response.expect_err("Expected an error when amount is 0"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn withdraw_btc_valid_params() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params.insert("address", BITCOIN_ADDR).unwrap(); - params.insert("amount", "0.1").unwrap(); - let response: Result, _> = client.request("withdraw_btc", params).await; - response.expect("Expected a HashMap, got an error"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params + .insert("address", "mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt") + .unwrap(); + params.insert("amount", 0.01).unwrap(); + let response: HashMap = client + .request("withdraw_btc", params) + .await + .expect("Expected a valid response"); + + assert_has_keys_hashmap(&response, &["signed_tx", "amount", "txid"]); + assert!(response.get("amount").unwrap().as_f64().unwrap(), 1_000_000); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn buy_xmr_no_params() { - let (client, _, _) = initialize_context().await; - let params = ObjectParams::new(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect_err("Expected an error when no params are given"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let params = ObjectParams::new(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when no params are given"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn buy_xmr_missing_seller() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params - .insert("bitcoin_change_address", BITCOIN_ADDR) - .unwrap(); - params - .insert("monero_receive_address", MONERO_ADDR) - .unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect_err("Expected an error when seller is missing"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when seller is missing"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn buy_xmr_missing_monero_address() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params - .insert("bitcoin_change_address", BITCOIN_ADDR) - .unwrap(); - params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect_err("Expected an error when monero_receive_address is missing"); -} + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when monero_receive_address is missing"); + + Ok(()) + }) + .await; +} #[tokio::test] #[serial] pub async fn buy_xmr_missing_bitcoin_address() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params - .insert("monero_receive_address", MONERO_ADDR) - .unwrap(); - params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect_err("Expected an error when bitcoin_change_address is missing"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when bitcoin_change_address is missing"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn buy_xmr_malformed_bitcoin_address() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params - .insert("bitcoin_change_address", "invalid_address") - .unwrap(); - params - .insert("monero_receive_address", MONERO_ADDR) - .unwrap(); - params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect_err("Expected an error when bitcoin_change_address is malformed"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, writer, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", "invalid_address") + .unwrap(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when bitcoin_change_address is malformed"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn buy_xmr_malformed_monero_address() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params - .insert("bitcoin_change_address", BITCOIN_ADDR) - .unwrap(); - params - .insert("monero_receive_address", "invalid_address") - .unwrap(); - params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect_err("Expected an error when monero_receive_address is malformed"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params + .insert("monero_receive_address", "invalid_address") + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when monero_receive_address is malformed"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn buy_xmr_malformed_seller() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params - .insert("bitcoin_change_address", BITCOIN_ADDR) - .unwrap(); - params - .insert("monero_receive_address", MONERO_ADDR) - .unwrap(); - params.insert("seller", "invalid_seller").unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect_err("Expected an error when seller is malformed"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + params.insert("seller", "invalid_seller").unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when seller is malformed"); + + Ok(()) + }) + .await; } -#[tokio::test] -#[serial] -pub async fn buy_xmr_valid_params() { - let (client, _, _) = initialize_context().await; - let mut params = ObjectParams::new(); - params - .insert("bitcoin_change_address", BITCOIN_ADDR) - .unwrap(); - params - .insert("monero_receive_address", MONERO_ADDR) - .unwrap(); - params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; - response.expect("Expected a HashMap, got an error"); -} - -#[tokio::test] -#[serial] pub async fn suspend_current_swap_no_swap_running() { - let (client, _, _) = initialize_context().await; - let response: Result, _> = client - .request("suspend_current_swap", ObjectParams::new()) - .await; - response.expect_err("Expected an error when no swap is running"); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, _) = setup_daemon(harness_ctx).await; + + let response: Result, _> = client + .request("suspend_current_swap", ObjectParams::new()) + .await; + response.expect_err("Expected an error when no swap is running"); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn suspend_current_swap_swap_running() { - let (client, _, ctx) = initialize_context().await; - ctx.swap_lock - .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) - .await - .unwrap(); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, ctx) = setup_daemon(harness_ctx).await; - tokio::spawn(async move { - // Immediately release lock when suspend signal is received. Mocks a running swap that is then cancelled. ctx.swap_lock - .listen_for_swap_force_suspension() + .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) .await .unwrap(); - ctx.swap_lock.release_swap_lock().await.unwrap(); - }); - let response: HashMap = client - .request("suspend_current_swap", ObjectParams::new()) - .await - .unwrap(); - assert_eq!( - response, - HashMap::from([("swapId".to_string(), SWAP_ID.to_string())]) - ); + tokio::spawn(async move { + // Immediately release lock when suspend signal is received. Mocks a running swap that is then cancelled. + ctx.swap_lock + .listen_for_swap_force_suspension() + .await + .unwrap(); + ctx.swap_lock.release_swap_lock().await.unwrap(); + }); + + let response: HashMap = client + .request("suspend_current_swap", ObjectParams::new()) + .await + .unwrap(); + assert_eq!( + response, + HashMap::from([("swapId".to_string(), SWAP_ID.to_string())]) + ); + + Ok(()) + }) + .await; } #[tokio::test] #[serial] pub async fn suspend_current_swap_timeout() { - let (client, _, ctx) = initialize_context().await; - ctx.swap_lock - .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) - .await - .unwrap(); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, ctx) = setup_daemon(harness_ctx).await; - let response: Result, _> = client - .request("suspend_current_swap", ObjectParams::new()) - .await; - response.expect_err("Expected an error when suspend signal times out"); + ctx.swap_lock + .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) + .await + .unwrap(); + + let response: Result, _> = client + .request("suspend_current_swap", ObjectParams::new()) + .await; + response.expect_err("Expected an error when suspend signal times out"); + + Ok(()) + }) + .await; +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_valid_params() { + setup_test(SlowCancelConfig, |mut harness_ctx| async move { + let alice_addr = harness_ctx.bob_params.get_concentenated_alice_address(); + let (change_address, receive_address) = + harness_ctx.bob_params.get_change_receive_addresses().await; + let (client, _, _) = setup_daemon(harness_ctx).await; + + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", change_address) + .unwrap(); + params + .insert("monero_receive_address", receive_address) + .unwrap(); + + params.insert("seller", alice_addr).unwrap(); + let response: HashMap = client + .request("buy_xmr", params) + .await + .expect("Expected a HashMap, got an error"); + + assert_has_keys_hashmap(&response, &["swapId"]); + + Ok(()) + }) + .await; } -*/