diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 4297f16a1c..7e28e515a5 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -1390,7 +1390,7 @@ impl SwapOps for EthCoin { } fn is_supported_by_watchers(&self) -> bool { - false + std::env::var("USE_WATCHER_REWARD").is_ok() //self.contract_supports_watchers } } @@ -1797,7 +1797,7 @@ impl WatcherOps for EthCoin { }, }; - let send_contract_reward_on_spend = true; + let send_contract_reward_on_spend = other_coin.is_eth(); Ok(Some(WatcherReward { amount, diff --git a/mm2src/coins/eth/eth_tests.rs b/mm2src/coins/eth/eth_tests.rs index e71821f785..5c2d844381 100644 --- a/mm2src/coins/eth/eth_tests.rs +++ b/mm2src/coins/eth/eth_tests.rs @@ -1,9 +1,13 @@ use super::*; use crate::IguanaPrivKey; -use common::{block_on, now_sec_u32}; +use common::{block_on, now_sec_u32, wait_until_sec}; +use crypto::privkey::key_pair_from_seed; +use ethkey::{Generator, Random}; use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; -use mm2_test_helpers::for_tests::{eth_jst_testnet_conf, eth_testnet_conf, ETH_DEV_NODE, ETH_DEV_SWAP_CONTRACT, - ETH_DEV_TOKEN_CONTRACT, ETH_MAINNET_NODE, ETH_MAINNET_SWAP_CONTRACT}; +use mm2_test_helpers::{for_tests::{eth_jst_testnet_conf, eth_testnet_conf, ETH_DEV_NODE, ETH_DEV_NODES, + ETH_DEV_SWAP_CONTRACT, ETH_DEV_TOKEN_CONTRACT, ETH_MAINNET_NODE, + ETH_MAINNET_SWAP_CONTRACT}, + get_passphrase}; use mocktopus::mocking::*; /// The gas price for the tests @@ -17,11 +21,62 @@ const GAS_PRICE_APPROXIMATION_ON_TRADE_PREIMAGE: u64 = 53_500_000_000; const TAKER_PAYMENT_SPEND_SEARCH_INTERVAL: f64 = 1.; +lazy_static! { + static ref ETH_DISTRIBUTOR: EthCoin = eth_distributor(); + static ref JST_DISTRIBUTOR: EthCoin = jst_distributor(); + static ref MM_CTX: MmArc = MmCtxBuilder::new().into_mm_arc(); +} + fn check_sum(addr: &str, expected: &str) { let actual = checksum_address(addr); assert_eq!(expected, actual); } +pub fn eth_distributor() -> EthCoin { + let req = json!({ + "method": "enable", + "coin": "ETH", + "urls": ETH_DEV_NODES, + "swap_contract_address": ETH_DEV_SWAP_CONTRACT, + }); + let seed = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); + let keypair = key_pair_from_seed(&seed).unwrap(); + let priv_key_policy = PrivKeyBuildPolicy::IguanaPrivKey(keypair.private().secret); + block_on(eth_coin_from_conf_and_request( + &MM_CTX, + "ETH", + ð_testnet_conf(), + &req, + CoinProtocol::ETH, + priv_key_policy, + )) + .unwrap() +} + +pub fn jst_distributor() -> EthCoin { + let req = json!({ + "method": "enable", + "coin": "ETH", + "urls": ETH_DEV_NODES, + "swap_contract_address": ETH_DEV_SWAP_CONTRACT, + }); + let seed = get_passphrase!(".env.client", "BOB_PASSPHRASE").unwrap(); + let keypair = key_pair_from_seed(&seed).unwrap(); + let priv_key_policy = PrivKeyBuildPolicy::IguanaPrivKey(keypair.private().secret); + block_on(eth_coin_from_conf_and_request( + &MM_CTX, + "ETH", + ð_testnet_conf(), + &req, + CoinProtocol::ERC20 { + platform: "ETH".to_string(), + contract_address: ETH_DEV_TOKEN_CONTRACT.to_string(), + }, + priv_key_policy, + )) + .unwrap() +} + fn eth_coin_for_test( coin_type: EthCoinType, urls: &[&str], @@ -31,7 +86,25 @@ fn eth_coin_for_test( &hex::decode("809465b17d0a4ddb3e4c69e8f23c2cabad868f51f8bed5c765ad1d6516c3306f").unwrap(), ) .unwrap(); + eth_coin_from_keypair(coin_type, urls, fallback_swap_contract, key_pair) +} +fn random_eth_coin_for_test( + coin_type: EthCoinType, + urls: &[&str], + fallback_swap_contract: Option
, +) -> (MmArc, EthCoin) { + let key_pair = Random.generate().unwrap(); + fill_eth(key_pair.address(), 0.001); + eth_coin_from_keypair(coin_type, urls, fallback_swap_contract, key_pair) +} + +fn eth_coin_from_keypair( + coin_type: EthCoinType, + urls: &[&str], + fallback_swap_contract: Option
, + key_pair: KeyPair, +) -> (MmArc, EthCoin) { let mut nodes = vec![]; for url in urls.iter() { nodes.push(HttpTransportNode { @@ -85,6 +158,24 @@ fn eth_coin_for_test( (ctx, eth_coin) } +pub fn fill_eth(to_addr: Address, amount: f64) { + let wei_per_eth: u64 = 1_000_000_000_000_000_000; + let amount_in_wei = (amount * wei_per_eth as f64) as u64; + ETH_DISTRIBUTOR + .send_to_address(to_addr, amount_in_wei.into()) + .wait() + .unwrap(); +} + +pub fn fill_jst(to_addr: Address, amount: f64) { + let wei_per_jst: u64 = 1_000_000_000_000_000_000; + let amount_in_wei = (amount * wei_per_jst as f64) as u64; + JST_DISTRIBUTOR + .send_to_address(to_addr, amount_in_wei.into()) + .wait() + .unwrap(); +} + #[test] /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#test-cases fn test_check_sum_address() { @@ -214,10 +305,9 @@ fn test_wei_from_big_decimal() { #[test] fn send_and_refund_erc20_payment() { - let key_pair = KeyPair::from_secret_slice( - &hex::decode("d27bfdbb5f89d30f8b7a1d0dcd4e181e54b8a2347836cb59c6570834f820f9a4").unwrap(), - ) - .unwrap(); + let key_pair = Random.generate().unwrap(); + fill_eth(key_pair.address(), 0.001); + fill_jst(key_pair.address(), 0.0001); let transport = Web3Transport::single_node(ETH_DEV_NODE, false); let web3 = Web3::new(transport); @@ -260,16 +350,15 @@ fn send_and_refund_erc20_payment() { time_lock, other_pubkey: &DEX_FEE_ADDR_RAW_PUBKEY, secret_hash, - amount: "0.001".parse().unwrap(), + amount: "0.0001".parse().unwrap(), swap_contract_address: &coin.swap_contract_address(), swap_unique_data: &[], payment_instructions: &None, watcher_reward: None, - wait_for_confirmation_until: 0, + wait_for_confirmation_until: wait_until_sec(15), }; let payment = coin.send_maker_payment(maker_payment_args).wait().unwrap(); log!("{:?}", payment); - block_on(Timer::sleep(5.)); let swap_id = coin.etomic_swap_id(time_lock, secret_hash); let status = block_on( @@ -296,7 +385,6 @@ fn send_and_refund_erc20_payment() { .wait() .unwrap(); log!("{:?}", refund); - block_on(Timer::sleep(5.)); let status = block_on( coin.payment_status( @@ -311,10 +399,8 @@ fn send_and_refund_erc20_payment() { #[test] fn send_and_refund_eth_payment() { - let key_pair = KeyPair::from_secret_slice( - &hex::decode("0b6d7b4b1b9454f3f0bc76b2988cd672439213a1de23d20a83467131366ba41c").unwrap(), - ) - .unwrap(); + let key_pair = Random.generate().unwrap(); + fill_eth(key_pair.address(), 0.001); let transport = Web3Transport::single_node(ETH_DEV_NODE, false); let web3 = Web3::new(transport); let ctx = MmCtxBuilder::new().into_mm_arc(); @@ -353,7 +439,7 @@ fn send_and_refund_eth_payment() { time_lock, other_pubkey: &DEX_FEE_ADDR_RAW_PUBKEY, secret_hash, - amount: "0.001".parse().unwrap(), + amount: "0.0001".parse().unwrap(), swap_contract_address: &coin.swap_contract_address(), swap_unique_data: &[], payment_instructions: &None, @@ -363,7 +449,6 @@ fn send_and_refund_eth_payment() { let payment = coin.send_maker_payment(send_maker_payment_args).wait().unwrap(); log!("{:?}", payment); - block_on(Timer::sleep(5.)); let swap_id = coin.etomic_swap_id(time_lock, secret_hash); let status = block_on( @@ -391,7 +476,6 @@ fn send_and_refund_eth_payment() { .unwrap(); log!("{:?}", refund); - block_on(Timer::sleep(5.)); let status = block_on( coin.payment_status( @@ -820,7 +904,7 @@ fn test_nonce_lock() { // send several transactions concurrently to check that they are not using same nonce // using real ETH dev node - let (ctx, coin) = eth_coin_for_test(EthCoinType::Eth, ETH_DEV_NODES, None); + let (ctx, coin) = random_eth_coin_for_test(EthCoinType::Eth, ETH_DEV_NODES, None); let mut futures = vec![]; for _ in 0..5 { futures.push( diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 9821173a7b..e54a8ad2bd 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -575,7 +575,7 @@ impl MakerSwap { }; // This will be done during order match - self.w().watcher_reward = false; + self.w().watcher_reward = std::env::var("USE_WATCHER_REWARD").is_ok(); Ok((Some(MakerSwapCommand::Negotiate), vec![MakerSwapEvent::Started(data)])) } diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 660629749a..b2ee236493 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1070,7 +1070,7 @@ impl TakerSwap { }; // This will be done during order match - self.w().watcher_reward = false; + self.w().watcher_reward = std::env::var("USE_WATCHER_REWARD").is_ok(); Ok((Some(TakerSwapCommand::Negotiate), vec![TakerSwapEvent::Started(data)])) } diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index 49157b79e8..82e9fb92c1 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -1,10 +1,10 @@ pub use common::{block_on, now_ms, now_sec, wait_until_ms, wait_until_sec}; pub use mm2_number::MmNumber; pub use mm2_test_helpers::for_tests::{check_my_swap_status, check_recent_swaps, check_stats_swap_status, - enable_native_bch, eth_sepolia_conf, jst_sepolia_conf, mm_dump, MarketMakerIt, - MAKER_ERROR_EVENTS, MAKER_SUCCESS_EVENTS, TAKER_ERROR_EVENTS, - TAKER_SUCCESS_EVENTS}; -use mm2_test_helpers::for_tests::{ETH_SEPOLIA_NODE, ETH_SEPOLIA_SWAP_CONTRACT, ETH_SEPOLIA_TOKEN_CONTRACT}; + enable_native, enable_native_bch, eth_jst_testnet_conf, eth_sepolia_conf, + eth_testnet_conf, jst_sepolia_conf, mm_dump, MarketMakerIt, ETH_DEV_NODES, + ETH_DEV_SWAP_CONTRACT, ETH_DEV_TOKEN_CONTRACT, MAKER_ERROR_EVENTS, + MAKER_SUCCESS_EVENTS, TAKER_ERROR_EVENTS, TAKER_SUCCESS_EVENTS}; pub use secp256k1::{PublicKey, SecretKey}; pub use std::env; pub use std::thread; @@ -31,7 +31,6 @@ use http::StatusCode; use keys::{Address, AddressHashEnum, KeyPair, NetworkPrefix as CashAddrPrefix}; use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; use mm2_number::BigDecimal; -use mm2_test_helpers::for_tests::{enable_native, eth_testnet_conf, ETH_DEV_NODES, ETH_DEV_SWAP_CONTRACT}; use mm2_test_helpers::structs::{MyBalanceResponse, TransactionDetails}; use primitives::hash::{H160, H256}; use script::Builder; @@ -165,19 +164,19 @@ pub fn _fill_eth(to_addr: &str) { } // Generates an ethereum coin in the sepolia network with the given seed -pub fn generate_eth_coin_with_seed(seed: &str) -> EthCoin { +pub fn _generate_eth_coin_with_seed(seed: &str) -> EthCoin { let req = json!({ "method": "enable", "coin": "ETH", - "urls": ETH_SEPOLIA_NODE, - "swap_contract_address": ETH_SEPOLIA_SWAP_CONTRACT, + "urls": ETH_DEV_NODES, + "swap_contract_address": ETH_DEV_SWAP_CONTRACT, }); let keypair = key_pair_from_seed(seed).unwrap(); let priv_key_policy = PrivKeyBuildPolicy::IguanaPrivKey(keypair.private().secret); block_on(eth_coin_from_conf_and_request( &MM_CTX, "ETH", - ð_sepolia_conf(), + ð_testnet_conf(), &req, CoinProtocol::ETH, priv_key_policy, @@ -189,8 +188,8 @@ pub fn generate_jst_with_seed(seed: &str) -> EthCoin { let req = json!({ "method": "enable", "coin": "JST", - "urls": ETH_SEPOLIA_NODE, - "swap_contract_address": ETH_SEPOLIA_SWAP_CONTRACT, + "urls": ETH_DEV_NODES, + "swap_contract_address": ETH_DEV_SWAP_CONTRACT, }); let keypair = key_pair_from_seed(seed).unwrap(); @@ -198,11 +197,11 @@ pub fn generate_jst_with_seed(seed: &str) -> EthCoin { block_on(eth_coin_from_conf_and_request( &MM_CTX, "JST", - &jst_sepolia_conf(), + ð_jst_testnet_conf(), &req, CoinProtocol::ERC20 { platform: "ETH".into(), - contract_address: String::from(ETH_SEPOLIA_TOKEN_CONTRACT), + contract_address: String::from(ETH_DEV_TOKEN_CONTRACT), }, priv_key_policy, )) diff --git a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs index ee71fa9033..4783eaf380 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs @@ -1,9 +1,9 @@ -use crate::docker_tests::docker_tests_common::{eth_distributor, generate_eth_coin_with_seed, generate_jst_with_seed}; +use crate::docker_tests::docker_tests_common::{eth_distributor, generate_jst_with_seed}; use crate::integration_tests_common::*; use crate::{generate_utxo_coin_with_privkey, generate_utxo_coin_with_random_privkey, random_secp256k1_secret}; use coins::coin_errors::ValidatePaymentError; use coins::utxo::{dhash160, UtxoCommonOps}; -use coins::{ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, MmCoin, MmCoinEnum, RefundPaymentArgs, +use coins::{ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, MmCoin, MmCoinEnum, RefundPaymentArgs, RewardTarget, SearchForSwapTxSpendInput, SendPaymentArgs, SwapOps, WatcherOps, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, EARLY_CONFIRMATION_ERR_LOG, INVALID_CONTRACT_ADDRESS_ERR_LOG, INVALID_PAYMENT_STATE_ERR_LOG, INVALID_RECEIVER_ERR_LOG, INVALID_REFUND_TX_ERR_LOG, @@ -16,17 +16,19 @@ use mm2_main::mm2::lp_swap::{dex_fee_amount, dex_fee_amount_from_taker_coin, dex MAKER_PAYMENT_SPEND_SENT_LOG, TAKER_PAYMENT_REFUND_SENT_LOG, WATCHER_MESSAGE_SENT_LOG}; use mm2_number::BigDecimal; use mm2_number::MmNumber; -use mm2_test_helpers::for_tests::{enable_eth_coin, eth_sepolia_conf, jst_sepolia_conf, mm_dump, my_balance, +use mm2_test_helpers::for_tests::{enable_eth_coin, eth_jst_testnet_conf, eth_testnet_conf, mm_dump, my_balance, mycoin1_conf, mycoin_conf, start_swaps, MarketMakerIt, Mm2TestConf, - DEFAULT_RPC_PASSWORD, ETH_SEPOLIA_NODE, ETH_SEPOLIA_SWAP_CONTRACT}; + DEFAULT_RPC_PASSWORD, ETH_DEV_NODES, ETH_DEV_SWAP_CONTRACT}; +use mm2_test_helpers::get_passphrase; use mm2_test_helpers::structs::WatcherConf; -use num_traits::Zero; +use num_traits::{One, Zero}; +use primitives::hash::H256; use std::str::FromStr; use std::thread; use std::time::Duration; use uuid::Uuid; -#[derive(Debug)] +#[derive(Debug, Clone)] struct BalanceResult { alice_acoin_balance_before: BigDecimal, alice_acoin_balance_middle: BigDecimal, @@ -58,9 +60,9 @@ fn enable_eth(mm_node: &MarketMakerIt, coin: &str) { dbg!(block_on(enable_eth_coin( mm_node, coin, - ETH_SEPOLIA_NODE, - ETH_SEPOLIA_SWAP_CONTRACT, - Some(ETH_SEPOLIA_SWAP_CONTRACT), + ETH_DEV_NODES, + ETH_DEV_SWAP_CONTRACT, + Some(ETH_DEV_SWAP_CONTRACT), true ))); } @@ -72,6 +74,7 @@ enum SwapFlow { TakerSpendsMakerPayment, } +#[allow(clippy::too_many_arguments)] fn start_swaps_and_get_balances( a_coin: &'static str, b_coin: &'static str, @@ -80,22 +83,18 @@ fn start_swaps_and_get_balances( volume: f64, envs: &[(&str, &str)], swap_flow: SwapFlow, + alice_privkey: &str, + bob_privkey: &str, + watcher_privkey: &str, ) -> BalanceResult { let coins = json!([ - eth_sepolia_conf(), - jst_sepolia_conf(), + eth_testnet_conf(), + eth_jst_testnet_conf(), mycoin_conf(1000), mycoin1_conf(1000) ]); - let alice_passphrase = if (a_coin == "MYCOIN" || a_coin == "MYCOIN1") && (b_coin == "MYCOIN" || b_coin == "MYCOIN1") - { - format!("0x{}", hex::encode(random_secp256k1_secret())) - } else { - String::from("spice describe gravity federal thank unfair blast come canal monkey style afraid") - }; - - let alice_conf = Mm2TestConf::seednode_using_watchers(&alice_passphrase, &coins); + let alice_conf = Mm2TestConf::seednode_using_watchers(&format!("0x{}", alice_privkey), &coins); let mut mm_alice = block_on(MarketMakerIt::start_with_envs( alice_conf.conf.clone(), alice_conf.rpc_password.clone(), @@ -106,13 +105,8 @@ fn start_swaps_and_get_balances( let (_alice_dump_log, _alice_dump_dashboard) = mm_alice.mm_dump(); log!("Alice log path: {}", mm_alice.log_path.display()); - let bob_passphrase = if (a_coin == "MYCOIN" || a_coin == "MYCOIN1") && b_coin == "MYCOIN" || b_coin == "MYCOIN1" { - format!("0x{}", hex::encode(random_secp256k1_secret())) - } else { - String::from("also shoot benefit prefer juice shell elder veteran woman mimic image kidney") - }; - - let bob_conf = Mm2TestConf::light_node_using_watchers(&bob_passphrase, &coins, &[&mm_alice.ip.to_string()]); + let bob_conf = + Mm2TestConf::light_node_using_watchers(&format!("0x{}", bob_privkey), &coins, &[&mm_alice.ip.to_string()]); let mut mm_bob = block_on(MarketMakerIt::start_with_envs( bob_conf.conf.clone(), bob_conf.rpc_password, @@ -123,13 +117,10 @@ fn start_swaps_and_get_balances( let (_bob_dump_log, _bob_dump_dashboard) = mm_bob.mm_dump(); log!("Bob log path: {}", mm_bob.log_path.display()); - let bob_keypair = key_pair_from_seed(&bob_passphrase).unwrap(); - let alice_keypair = key_pair_from_seed(&alice_passphrase).unwrap(); - - generate_utxo_coin_with_privkey("MYCOIN", 100.into(), bob_keypair.private().secret); - generate_utxo_coin_with_privkey("MYCOIN", 100.into(), alice_keypair.private().secret); - generate_utxo_coin_with_privkey("MYCOIN1", 100.into(), bob_keypair.private().secret); - generate_utxo_coin_with_privkey("MYCOIN1", 100.into(), alice_keypair.private().secret); + generate_utxo_coin_with_privkey("MYCOIN", 100.into(), H256::from_str(bob_privkey).unwrap()); + generate_utxo_coin_with_privkey("MYCOIN", 100.into(), H256::from_str(alice_privkey).unwrap()); + generate_utxo_coin_with_privkey("MYCOIN1", 100.into(), H256::from_str(bob_privkey).unwrap()); + generate_utxo_coin_with_privkey("MYCOIN1", 100.into(), H256::from_str(alice_privkey).unwrap()); let (watcher_conf, watcher_log_to_wait) = match swap_flow { SwapFlow::WatcherSpendsMakerPayment => ( @@ -161,10 +152,13 @@ fn start_swaps_and_get_balances( ), }; - let watcher_passphrase = - String::from("also shoot benefit prefer juice shell thank unfair canal monkey style afraid"); - let watcher_conf = - Mm2TestConf::watcher_light_node(&watcher_passphrase, &coins, &[&mm_alice.ip.to_string()], watcher_conf).conf; + let watcher_conf = Mm2TestConf::watcher_light_node( + &format!("0x{}", watcher_privkey), + &coins, + &[&mm_alice.ip.to_string()], + watcher_conf, + ) + .conf; let mut mm_watcher = block_on(MarketMakerIt::start_with_envs( watcher_conf, @@ -209,18 +203,18 @@ fn start_swaps_and_get_balances( )); if matches!(swap_flow, SwapFlow::WatcherRefundsTakerPayment) { - block_on(mm_bob.wait_for_log(100., |log| log.contains(MAKER_PAYMENT_SENT_LOG))).unwrap(); + block_on(mm_bob.wait_for_log(120., |log| log.contains(MAKER_PAYMENT_SENT_LOG))).unwrap(); block_on(mm_bob.stop()).unwrap(); } if !matches!(swap_flow, SwapFlow::TakerSpendsMakerPayment) { - block_on(mm_alice.wait_for_log(100., |log| log.contains("Taker payment confirmed"))).unwrap(); + block_on(mm_alice.wait_for_log(120., |log| log.contains("Taker payment confirmed"))).unwrap(); alice_acoin_balance_middle = block_on(my_balance(&mm_alice, a_coin)).balance; alice_bcoin_balance_middle = block_on(my_balance(&mm_alice, b_coin)).balance; alice_eth_balance_middle = block_on(my_balance(&mm_alice, "ETH")).balance; block_on(mm_alice.stop()).unwrap(); } - block_on(mm_watcher.wait_for_log(100., |log| log.contains(watcher_log_to_wait))).unwrap(); + block_on(mm_watcher.wait_for_log(120., |log| log.contains(watcher_log_to_wait))).unwrap(); thread::sleep(Duration::from_secs(20)); let mm_alice = MarketMakerIt::start(alice_conf.conf, alice_conf.rpc_password, None).unwrap(); @@ -263,6 +257,10 @@ fn start_swaps_and_get_balances( #[test] fn test_watcher_spends_maker_payment_utxo_utxo() { + let alice_privkey = hex::encode(random_secp256k1_secret()); + let bob_privkey = hex::encode(random_secp256k1_secret()); + let watcher_privkey = hex::encode(random_secp256k1_secret()); + let balances = start_swaps_and_get_balances( "MYCOIN", "MYCOIN1", @@ -271,6 +269,9 @@ fn test_watcher_spends_maker_payment_utxo_utxo() { 2., &[], SwapFlow::WatcherSpendsMakerPayment, + &alice_privkey, + &bob_privkey, + &watcher_privkey, ); let acoin_volume = BigDecimal::from_str("50").unwrap(); @@ -295,16 +296,22 @@ fn test_watcher_spends_maker_payment_utxo_utxo() { } #[test] -#[ignore] fn test_watcher_spends_maker_payment_utxo_eth() { + let alice_privkey = "0af1b1a4cdfbec12c9014e2422c8819e02e5d0f6539f8bf15190d3ea592e4f14"; + let bob_privkey = "3245331f141578d8c4604639deb1e6f38f107a65642525ef32387325a079a463"; + let watcher_privkey = "9d1d86be257b3bd2504757689d0da24dd052fdff0641be073f1ea8aa5cccf597"; + let balances = start_swaps_and_get_balances( "ETH", "MYCOIN", 0.01, 0.01, 1., - &[], + &[("USE_WATCHER_REWARD", "")], SwapFlow::WatcherSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); let mycoin_volume = BigDecimal::from_str("1").unwrap(); @@ -322,16 +329,22 @@ fn test_watcher_spends_maker_payment_utxo_eth() { } #[test] -#[ignore] fn test_watcher_spends_maker_payment_eth_utxo() { + let alice_privkey = "0591b2acbe4798c6156a26bc8106c36d6fc09a85c9e02710eec32c1b41f047ec"; + let bob_privkey = "b6e59dee1112486573989f07d480691ca7e3eab81b499fe801d94b65ea1f1341"; + let watcher_privkey = "dc8ad0723a6a2c02d3239e8b009d4de6f3f0ad8b9bc51838cbed41edb378dd86"; + let balances = start_swaps_and_get_balances( "MYCOIN", "ETH", 100., 100., 0.01, - &[("TEST_COIN_PRICE", "0.01")], + &[("TEST_COIN_PRICE", "0.01"), ("USE_WATCHER_REWARD", "")], SwapFlow::WatcherSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); let eth_volume = BigDecimal::from_str("0.01").unwrap(); @@ -362,16 +375,22 @@ fn test_watcher_spends_maker_payment_eth_utxo() { } #[test] -#[ignore] fn test_watcher_spends_maker_payment_eth_erc20() { + let alice_privkey = "92ee1f48f07dcaab03ff3d5077211912fdf2229bb401e7a969f73fc2c3d4fe3f"; + let bob_privkey = "59e8c09c3aace4eb9301b2f70547fc0936be2bc662b9c0a7a625b5e8929491c7"; + let watcher_privkey = "e0915d112440fdc58405faace4626a983bb3fd8cb51f0e5a7ed8565b552b5751"; + let balances = start_swaps_and_get_balances( "JST", "ETH", 100., 100., 0.01, - &[("TEST_COIN_PRICE", "0.01")], + &[("TEST_COIN_PRICE", "0.01"), ("USE_WATCHER_REWARD", "")], SwapFlow::WatcherSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); let eth_volume = BigDecimal::from_str("0.01").unwrap(); @@ -389,9 +408,23 @@ fn test_watcher_spends_maker_payment_eth_erc20() { } #[test] -#[ignore] fn test_watcher_spends_maker_payment_erc20_eth() { - let balances = start_swaps_and_get_balances("ETH", "JST", 0.01, 0.01, 1., &[], SwapFlow::WatcherSpendsMakerPayment); + let alice_privkey = "2fd8d83e3b9799fa0a02cdaf6776dd36eee3243a62d399a54dc9a68f5e77b27c"; + let bob_privkey = "6425a922265573100165b60ff380fba5035c7406169087a43aefdee66aceccc1"; + let watcher_privkey = "b9b5fa738dcf7c99073b0f7d518a50b72139a7636ba3488766944fd3dc4df646"; + + let balances = start_swaps_and_get_balances( + "ETH", + "JST", + 0.01, + 0.01, + 1., + &[("USE_WATCHER_REWARD", "")], + SwapFlow::WatcherSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, + ); let jst_volume = BigDecimal::from_str("1").unwrap(); let eth_volume = BigDecimal::from_str("0.01").unwrap(); @@ -408,16 +441,22 @@ fn test_watcher_spends_maker_payment_erc20_eth() { } #[test] -#[ignore] fn test_watcher_spends_maker_payment_utxo_erc20() { + let alice_privkey = "e4fc65b69c323312ee3ba46406671bc9f2d524190621d82eeb51452701cfe43b"; + let bob_privkey = "721fc6b7f56495f7f721e1e11cddcaf593351264705c4044e83656f06eb595ef"; + let watcher_privkey = "a1f1c2666be032492a3cb772abc8a2845adfd6dca299fbed13416ccc6feb57ee"; + let balances = start_swaps_and_get_balances( "JST", "MYCOIN", 1., 1., 1., - &[("TEST_COIN_PRICE", "0.01")], + &[("TEST_COIN_PRICE", "0.01"), ("USE_WATCHER_REWARD", "")], SwapFlow::WatcherSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); let mycoin_volume = BigDecimal::from_str("1").unwrap(); @@ -435,16 +474,22 @@ fn test_watcher_spends_maker_payment_utxo_erc20() { } #[test] -#[ignore] fn test_watcher_spends_maker_payment_erc20_utxo() { + let alice_privkey = "5c9fbc69376c3ee6bb56d8d2b715f24b3bb92ccd47e93332d4d94899aa9fc7ae"; + let bob_privkey = "ccc24b9653087d939949d513756cefe1eff657de4c5bf34febc97843a6b26782"; + let watcher_privkey = "a1f1c2666be032492a3cb772abc8a2845adfd6dca299fbed13416ccc6feb57ee"; + let balances = start_swaps_and_get_balances( "MYCOIN", "JST", 1., 1., 1., - &[("TEST_COIN_PRICE", "0.01")], + &[("TEST_COIN_PRICE", "0.01"), ("USE_WATCHER_REWARD", "")], SwapFlow::WatcherSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); let mycoin_volume = BigDecimal::from_str("1").unwrap(); @@ -463,7 +508,8 @@ fn test_watcher_spends_maker_payment_erc20_utxo() { - mycoin_volume.clone() - dex_fee.with_scale(8); - let bob_jst_reward_sent = balances.bob_bcoin_balance_before - jst_volume.clone() - balances.bob_bcoin_balance_after; + let bob_jst_reward_sent = + balances.bob_bcoin_balance_before - jst_volume.clone() - balances.bob_bcoin_balance_after.clone(); assert_eq!( balances.alice_bcoin_balance_after, @@ -481,6 +527,10 @@ fn test_watcher_spends_maker_payment_erc20_utxo() { #[test] fn test_watcher_refunds_taker_payment_utxo() { + let alice_privkey = &hex::encode(random_secp256k1_secret()); + let bob_privkey = &hex::encode(random_secp256k1_secret()); + let watcher_privkey = &hex::encode(random_secp256k1_secret()); + let balances = start_swaps_and_get_balances( "MYCOIN1", "MYCOIN", @@ -489,6 +539,9 @@ fn test_watcher_refunds_taker_payment_utxo() { 2., &[("USE_TEST_LOCKTIME", "")], SwapFlow::WatcherRefundsTakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); assert_eq!( @@ -499,16 +552,22 @@ fn test_watcher_refunds_taker_payment_utxo() { } #[test] -#[ignore] fn test_watcher_refunds_taker_payment_eth() { + let alice_privkey = "0816c0558b934fafa845946bdd2b3163fe6b928e6160ea9aa10a8bea221e3813"; + let bob_privkey = "e5cb76954c5160d7df5bfa5798540d3583c73c9daa46903b98abb9eed2edecc6"; + let watcher_privkey = "ccd7f2c0da8f6428b60b42a27c0e37af59abd42251773156f4f59c5d16855f8c"; + let balances = start_swaps_and_get_balances( "ETH", "JST", 0.01, 0.01, 1., - &[("USE_TEST_LOCKTIME", "")], + &[("USE_TEST_LOCKTIME", ""), ("USE_WATCHER_REWARD", "")], SwapFlow::WatcherRefundsTakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); assert_eq!( balances.alice_acoin_balance_after.with_scale(2), @@ -519,16 +578,26 @@ fn test_watcher_refunds_taker_payment_eth() { } #[test] -#[ignore] fn test_watcher_refunds_taker_payment_erc20() { + let alice_privkey = "82c1bb28bb13488f901eff67f886e9895c4dfa28e3e24f1ed7873a73231c9492"; + let bob_privkey = "9a4721db00336ea0d8b7a373cdbdefc321285e7959fff8aea493af6f485b683f"; + let watcher_privkey = "8fdf25f087140b2797deb2a1d3ce66bd59e2449cc805b99958b3bfa8cd621eb8"; + let balances = start_swaps_and_get_balances( "JST", "ETH", 100., 100., 0.01, - &[("USE_TEST_LOCKTIME", ""), ("TEST_COIN_PRICE", "0.01")], + &[ + ("USE_TEST_LOCKTIME", ""), + ("TEST_COIN_PRICE", "0.01"), + ("USE_WATCHER_REWARD", ""), + ], SwapFlow::WatcherRefundsTakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); let jst_volume = BigDecimal::from_str("1").unwrap(); @@ -542,6 +611,10 @@ fn test_watcher_refunds_taker_payment_erc20() { #[test] fn test_watcher_waits_for_taker_utxo() { + let alice_privkey = &hex::encode(random_secp256k1_secret()); + let bob_privkey = &hex::encode(random_secp256k1_secret()); + let watcher_privkey = &hex::encode(random_secp256k1_secret()); + start_swaps_and_get_balances( "MYCOIN1", "MYCOIN", @@ -550,27 +623,36 @@ fn test_watcher_waits_for_taker_utxo() { 2., &[], SwapFlow::TakerSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); } #[test] -#[ignore] fn test_watcher_waits_for_taker_eth() { + let alice_privkey = "814ea055c807c1ff2d49c81abfc3434fa0d10a427369b1f8d60fc78ab1da7d16"; + let bob_privkey = "36533ec51a61f4b32856c8ce2ee811a263c625ae26e45ee68e6d28b65c8f9298"; + let watcher_privkey = "baa1c83a0993ba96f88ffc943919991792ce9e2498fc41f42b38030915d58f9f"; + start_swaps_and_get_balances( "JST", "ETH", 100., 100., 0.01, - &[("TEST_COIN_PRICE", "0.01")], + &[("TEST_COIN_PRICE", "0.01"), ("USE_WATCHER_REWARD", "")], SwapFlow::TakerSpendsMakerPayment, + alice_privkey, + bob_privkey, + watcher_privkey, ); } #[test] #[ignore] fn test_two_watchers_spend_maker_payment_eth_erc20() { - let coins = json!([eth_sepolia_conf(), jst_sepolia_conf()]); + let coins = json!([eth_testnet_conf(), eth_jst_testnet_conf()]); let alice_passphrase = String::from("spice describe gravity federal blast come thank unfair canal monkey style afraid"); @@ -785,7 +867,6 @@ fn test_watcher_validate_taker_fee_utxo() { } #[test] -#[ignore] // https://github.com/KomodoPlatform/atomicDEX-API/issues/1712 fn test_watcher_validate_taker_fee_eth() { let timeout = wait_until_sec(120); // timeout if test takes more than 120 seconds to run let lock_duration = get_payment_locktime(); @@ -794,7 +875,7 @@ fn test_watcher_validate_taker_fee_eth() { let taker_keypair = taker_coin.derive_htlc_key_pair(&[]); let taker_pubkey = taker_keypair.public(); - let taker_amount = MmNumber::from((10, 1)); + let taker_amount = MmNumber::from((1, 1)); let fee_amount = dex_fee_amount_from_taker_coin(&MmCoinEnum::EthCoin(taker_coin.clone()), "ETH", &taker_amount); let taker_fee = taker_coin .send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, fee_amount.into(), Uuid::new_v4().as_bytes()) @@ -888,17 +969,16 @@ fn test_watcher_validate_taker_fee_eth() { } #[test] -#[ignore] fn test_watcher_validate_taker_fee_erc20() { let timeout = wait_until_sec(120); // timeout if test takes more than 120 seconds to run let lock_duration = get_payment_locktime(); - let seed = String::from("spice describe gravity federal thank unfair blast come canal monkey style afraid"); + let seed = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let taker_coin = generate_jst_with_seed(&seed); let taker_keypair = taker_coin.derive_htlc_key_pair(&[]); let taker_pubkey = taker_keypair.public(); - let taker_amount = MmNumber::from((10, 1)); + let taker_amount = MmNumber::from((1, 1)); let fee_amount = dex_fee_amount_from_taker_coin(&MmCoinEnum::EthCoin(taker_coin.clone()), "ETH", &taker_amount); let taker_fee = taker_coin .send_taker_fee(&DEX_FEE_ADDR_RAW_PUBKEY, fee_amount.into(), Uuid::new_v4().as_bytes()) @@ -1203,16 +1283,15 @@ fn test_watcher_validate_taker_payment_utxo() { } #[test] -#[ignore] fn test_watcher_validate_taker_payment_eth() { let timeout = wait_until_sec(120); // timeout if test takes more than 120 seconds to run - let seed = String::from("spice describe gravity federal thank unfair blast come canal monkey style afraid"); - let taker_coin = generate_eth_coin_with_seed(&seed); + let taker_coin = eth_distributor(); let taker_keypair = taker_coin.derive_htlc_key_pair(&[]); let taker_pub = taker_keypair.public(); - let maker_keypair = key_pair_from_secret(random_secp256k1_secret().as_slice()).unwrap(); + let maker_seed = get_passphrase!(".env.client", "BOB_PASSPHRASE").unwrap(); + let maker_keypair = key_pair_from_seed(&maker_seed).unwrap(); let maker_pub = maker_keypair.public(); let time_lock_duration = get_payment_locktime(); @@ -1447,16 +1526,16 @@ fn test_watcher_validate_taker_payment_eth() { } #[test] -#[ignore] fn test_watcher_validate_taker_payment_erc20() { let timeout = wait_until_sec(120); // timeout if test takes more than 120 seconds to run - let seed = String::from("spice describe gravity federal thank unfair blast come canal monkey style afraid"); + let seed = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let taker_coin = generate_jst_with_seed(&seed); let taker_keypair = taker_coin.derive_htlc_key_pair(&[]); let taker_pub = taker_keypair.public(); - let maker_keypair = key_pair_from_secret(random_secp256k1_secret().as_slice()).unwrap(); + let maker_seed = get_passphrase!(".env.client", "BOB_PASSPHRASE").unwrap(); + let maker_keypair = key_pair_from_seed(&maker_seed).unwrap(); let maker_pub = maker_keypair.public(); let time_lock_duration = get_payment_locktime(); @@ -1465,13 +1544,13 @@ fn test_watcher_validate_taker_payment_erc20() { let secret_hash = dhash160(&MakerSwap::generate_secret().unwrap()); - let taker_amount = BigDecimal::from(10); - let maker_amount = BigDecimal::from(10); + let taker_amount = BigDecimal::from_str("0.01").unwrap(); + let maker_amount = BigDecimal::from_str("0.01").unwrap(); let watcher_reward = Some( block_on(taker_coin.get_taker_watcher_reward( &MmCoinEnum::from(taker_coin.clone()), - Some(taker_amount), + Some(taker_amount.clone()), Some(maker_amount), None, wait_for_confirmation_until, @@ -1485,7 +1564,7 @@ fn test_watcher_validate_taker_payment_erc20() { time_lock, other_pubkey: maker_pub, secret_hash: secret_hash.as_slice(), - amount: BigDecimal::from(10), + amount: taker_amount.clone(), swap_contract_address: &taker_coin.swap_contract_address(), swap_unique_data: &[], payment_instructions: &None, @@ -1551,7 +1630,7 @@ fn test_watcher_validate_taker_payment_erc20() { time_lock, other_pubkey: maker_pub, secret_hash: secret_hash.as_slice(), - amount: BigDecimal::from(10), + amount: taker_amount.clone(), swap_contract_address: &Some("9130b257d37a52e52f21054c4da3450c72f595ce".into()), swap_unique_data: &[], payment_instructions: &None, @@ -1621,7 +1700,7 @@ fn test_watcher_validate_taker_payment_erc20() { time_lock, other_pubkey: maker_pub, secret_hash: wrong_secret_hash.as_slice(), - amount: BigDecimal::from(10), + amount: taker_amount, swap_contract_address: &taker_coin.swap_contract_address(), swap_unique_data: &[], payment_instructions: &None, @@ -1765,3 +1844,86 @@ fn test_send_taker_payment_refund_preimage_utxo() { .unwrap(); assert_eq!(FoundSwapTxSpend::Refunded(refund_tx), found); } + +#[test] +fn test_watcher_reward() { + let timeout = wait_until_sec(300); // timeout if test takes more than 300 seconds to run + let (_ctx, utxo_coin, _) = generate_utxo_coin_with_random_privkey("MYCOIN", 1000u64.into()); + let eth_coin = eth_distributor(); + + let watcher_reward = + block_on(eth_coin.get_taker_watcher_reward(&MmCoinEnum::EthCoin(eth_coin.clone()), None, None, None, timeout)) + .unwrap(); + assert!(!watcher_reward.is_exact_amount); + assert!(matches!(watcher_reward.reward_target, RewardTarget::Contract)); + assert!(!watcher_reward.send_contract_reward_on_spend); + + let watcher_reward = block_on(eth_coin.get_taker_watcher_reward( + &MmCoinEnum::EthCoin(eth_coin.clone()), + None, + None, + Some(BigDecimal::one()), + timeout, + )) + .unwrap(); + assert!(watcher_reward.is_exact_amount); + assert!(matches!(watcher_reward.reward_target, RewardTarget::Contract)); + assert!(!watcher_reward.send_contract_reward_on_spend); + assert_eq!(watcher_reward.amount, BigDecimal::one()); + + let watcher_reward = block_on(eth_coin.get_taker_watcher_reward( + &MmCoinEnum::UtxoCoin(utxo_coin.clone()), + None, + None, + None, + timeout, + )) + .unwrap(); + assert!(!watcher_reward.is_exact_amount); + assert!(matches!(watcher_reward.reward_target, RewardTarget::PaymentSender)); + assert!(!watcher_reward.send_contract_reward_on_spend); + + let watcher_reward = + block_on(eth_coin.get_maker_watcher_reward(&MmCoinEnum::EthCoin(eth_coin.clone()), None, timeout)) + .unwrap() + .unwrap(); + assert!(!watcher_reward.is_exact_amount); + assert!(matches!(watcher_reward.reward_target, RewardTarget::None)); + assert!(watcher_reward.send_contract_reward_on_spend); + + let watcher_reward = block_on(eth_coin.get_maker_watcher_reward( + &MmCoinEnum::EthCoin(eth_coin.clone()), + Some(BigDecimal::one()), + timeout, + )) + .unwrap() + .unwrap(); + assert!(watcher_reward.is_exact_amount); + assert!(matches!(watcher_reward.reward_target, RewardTarget::None)); + assert!(watcher_reward.send_contract_reward_on_spend); + assert_eq!(watcher_reward.amount, BigDecimal::one()); + + let watcher_reward = + block_on(eth_coin.get_maker_watcher_reward(&MmCoinEnum::UtxoCoin(utxo_coin.clone()), None, timeout)) + .unwrap() + .unwrap(); + assert!(!watcher_reward.is_exact_amount); + assert!(matches!(watcher_reward.reward_target, RewardTarget::PaymentSpender)); + assert!(!watcher_reward.send_contract_reward_on_spend); + + let watcher_reward = block_on(utxo_coin.get_taker_watcher_reward( + &MmCoinEnum::EthCoin(eth_coin), + Some(BigDecimal::from_str("0.01").unwrap()), + Some(BigDecimal::from_str("1").unwrap()), + None, + timeout, + )) + .unwrap(); + assert!(!watcher_reward.is_exact_amount); + assert!(matches!(watcher_reward.reward_target, RewardTarget::PaymentReceiver)); + assert!(!watcher_reward.send_contract_reward_on_spend); + + let watcher_reward = + block_on(utxo_coin.get_maker_watcher_reward(&MmCoinEnum::UtxoCoin(utxo_coin.clone()), None, timeout)).unwrap(); + assert!(matches!(watcher_reward, None)); +} diff --git a/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs b/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs index 65a4723bc6..053c26ccd7 100644 --- a/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs +++ b/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs @@ -1005,7 +1005,6 @@ fn test_withdraw_and_send() { "-0.00101", 0.001, ); - // dev chain gas price is 0 so ETH expected balance change doesn't include the fee withdraw_and_send( &mm_alice, "ETH", @@ -1014,6 +1013,8 @@ fn test_withdraw_and_send() { "-0.001", 0.001, ); + log!("Wait for the ETH payment to be sent"); + thread::sleep(Duration::from_secs(15)); withdraw_and_send( &mm_alice, "JST", diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index d0749cc919..6908fcc964 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -1618,7 +1618,6 @@ pub async fn enable_eth_coin( "method": "enable", "coin": coin, "urls": urls, - "chain_id": 5, "swap_contract_address": swap_contract_address, "fallback_swap_contract": fallback_swap_contract, "mm2": 1,