From d48cc250667251a2d19a7bdf8c01e462e3f9833f Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 26 Dec 2024 18:36:45 +0700 Subject: [PATCH] eth-eth kickstart test --- .../tests/docker_tests/docker_tests_common.rs | 3 +- .../tests/docker_tests/eth_docker_tests.rs | 146 ++++++++++++++++-- mm2src/mm2_test_helpers/src/for_tests.rs | 55 ++++++- 3 files changed, 191 insertions(+), 13 deletions(-) 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 3050f22826..311800bb5d 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -1313,8 +1313,7 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } - let dex_fee_addr = addr_from_raw_pubkey(&DEX_FEE_ADDR_RAW_PUBKEY).unwrap(); - let dex_fee_addr = Token::Address(dex_fee_addr); + let dex_fee_addr = Token::Address(GETH_ACCOUNT); let params = ethabi::encode(&[dex_fee_addr]); let taker_swap_v2_data = format!("{}{}", TAKER_SWAP_V2_BYTES, hex::encode(params)); diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index d922ba8f27..8aec7ceed5 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -28,12 +28,13 @@ use coins::{CoinProtocol, CoinWithDerivationMethod, CommonSwapOpsV2, ConfirmPaym use common::{block_on, block_on_f01, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; -#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] use mm2_core::mm_ctx::MmArc; use mm2_number::{BigDecimal, BigUint}; -use mm2_test_helpers::for_tests::{account_balance, disable_coin, enable_erc20_token_v2, enable_eth_with_tokens_v2, - erc20_dev_conf, eth_dev_conf, get_new_address, get_token_info, nft_dev_conf, - MarketMakerIt, Mm2TestConf}; +use mm2_test_helpers::for_tests::{account_balance, active_swaps, coins_needed_for_kickstart, disable_coin, + enable_erc20_token_v2, enable_eth_coin_v2, enable_eth_with_tokens_v2, + erc20_dev_conf, eth1_dev_conf, eth_dev_conf, get_locked_amount, get_new_address, + get_token_info, mm_dump, my_swap_status, nft_dev_conf, start_swaps, MarketMakerIt, + Mm2TestConf, SwapV2TestContracts, TestNode}; #[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] use mm2_test_helpers::for_tests::{eth_sepolia_conf, sepolia_erc20_dev_conf}; use mm2_test_helpers::structs::{Bip44Chain, EnableCoinBalanceMap, EthWithTokensActivationResult, HDAccountAddressId, @@ -43,6 +44,7 @@ use serde_json::Value as Json; use std::str::FromStr; use std::thread; use std::time::Duration; +use uuid::Uuid; use web3::contract::{Contract, Options}; use web3::ethabi::Token; #[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] @@ -55,6 +57,7 @@ const SEPOLIA_MAKER_PRIV: &str = "6e2f3a6223b928a05a3a3622b0c3f3573d03663b704a61 const SEPOLIA_TAKER_PRIV: &str = "e0be82dca60ff7e4c6d6db339ac9e1ae249af081dba2110bddd281e711608f16"; const NFT_ETH: &str = "NFT_ETH"; const ETH: &str = "ETH"; +const ETH1: &str = "ETH1"; #[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] const ERC20: &str = "ERC20DEV"; @@ -1427,15 +1430,16 @@ impl SwapAddresses { } } -#[allow(dead_code)] /// Needed for eth or erc20 v2 activation in Geth tests fn eth_coin_v2_activation_with_random_privkey( + ctx: &MmArc, ticker: &str, conf: &Json, swap_addr: SwapAddresses, erc20: bool, -) -> EthCoin { - let build_policy = EthPrivKeyBuildPolicy::IguanaPrivKey(random_secp256k1_secret()); +) -> (EthCoin, Secp256k1Secret) { + let priv_key = random_secp256k1_secret(); + let build_policy = EthPrivKeyBuildPolicy::IguanaPrivKey(priv_key); let node = EthNode { url: GETH_RPC_URL.to_string(), komodo_proxy: false, @@ -1455,7 +1459,7 @@ fn eth_coin_v2_activation_with_random_privkey( gap_limit: None, }; let coin = block_on(eth_coin_from_conf_and_request_v2( - &MM_CTX1, + ctx, ticker, conf, platform_request, @@ -1471,9 +1475,9 @@ fn eth_coin_v2_activation_with_random_privkey( token_addr: erc20_contract(), }; let coin = block_on(coin.set_coin_type(coin_type)); - return coin; + return (coin, priv_key); } - coin + (coin, priv_key) } #[cfg(feature = "sepolia-taker-swap-v2-tests")] @@ -2749,3 +2753,125 @@ fn test_enable_custom_erc20_with_duplicate_contract_in_config() { // Disable the custom token, this to check that it was enabled correctly block_on(disable_coin(&mm_hd, &config_ticker, true)); } + +#[test] +fn test_v2_eth_eth_kickstart() { + // Initialize swap addresses and configurations + let swap_addresses = SwapAddresses::init(); + let contracts = SwapV2TestContracts { + maker_swap_v2_contract: eth_addr_to_hex(&swap_addresses.swap_v2_contracts.maker_swap_v2_contract), + taker_swap_v2_contract: eth_addr_to_hex(&swap_addresses.swap_v2_contracts.taker_swap_v2_contract), + nft_maker_swap_v2_contract: eth_addr_to_hex(&swap_addresses.swap_v2_contracts.nft_maker_swap_v2_contract), + }; + let swap_contract_address = eth_addr_to_hex(&swap_addresses.swap_contract_address); + let node = TestNode { + url: GETH_RPC_URL.to_string(), + }; + + // Helper function for activating coins + let enable_coins = |mm: &MarketMakerIt, coins: &[&str]| { + for &coin in coins { + log!( + "{:?}", + block_on(enable_eth_coin_v2( + mm, + coin, + &swap_contract_address, + contracts.clone(), + None, + &[node.clone()] + )) + ); + } + }; + + // start Bob and Alice + let (_, bob_priv_key) = + eth_coin_v2_activation_with_random_privkey(&MM_CTX, ETH, ð_dev_conf(), swap_addresses, false); + let (_, alice_priv_key) = + eth_coin_v2_activation_with_random_privkey(&MM_CTX1, ETH1, ð1_dev_conf(), swap_addresses, false); + let coins = json!([eth_dev_conf(), eth1_dev_conf()]); + + let mut bob_conf = Mm2TestConf::seednode_trade_v2(&format!("0x{}", hex::encode(bob_priv_key)), &coins); + let mut mm_bob = MarketMakerIt::start(bob_conf.conf.clone(), bob_conf.rpc_password.clone(), None).unwrap(); + let (_bob_dump_log, _bob_dump_dashboard) = mm_dump(&mm_bob.log_path); + log!("Bob log path: {}", mm_bob.log_path.display()); + + let mut alice_conf = + Mm2TestConf::light_node_trade_v2(&format!("0x{}", hex::encode(alice_priv_key)), &coins, &[&mm_bob + .ip + .to_string()]); + let mut mm_alice = MarketMakerIt::start(alice_conf.conf.clone(), alice_conf.rpc_password.clone(), None).unwrap(); + let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path); + log!("Alice log path: {}", mm_alice.log_path.display()); + + // Enable ETH and ETH1 for both Bob and Alice + enable_coins(&mm_bob, &[ETH, ETH1]); + enable_coins(&mm_alice, &[ETH, ETH1]); + + let uuids = block_on(start_swaps(&mut mm_bob, &mut mm_alice, &[(ETH, ETH1)], 1.0, 1.0, 77.)); + log!("{:?}", uuids); + let parsed_uuids: Vec = uuids.iter().map(|u| u.parse().unwrap()).collect(); + + for uuid in uuids.iter() { + log_swap_status_before_stop(&mm_bob, uuid, "Maker"); + log_swap_status_before_stop(&mm_alice, uuid, "Taker"); + } + + block_on(mm_bob.stop()).unwrap(); + block_on(mm_alice.stop()).unwrap(); + + // Restart Bob and Alice + bob_conf.conf["dbdir"] = mm_bob.folder.join("DB").to_str().unwrap().into(); + bob_conf.conf["log"] = mm_bob.folder.join("mm2_dup.log").to_str().unwrap().into(); + + let mm_bob = MarketMakerIt::start(bob_conf.conf, bob_conf.rpc_password, None).unwrap(); + let (_bob_dump_log, _bob_dump_dashboard) = mm_dump(&mm_bob.log_path); + log!("Bob log path: {}", mm_bob.log_path.display()); + + alice_conf.conf["dbdir"] = mm_alice.folder.join("DB").to_str().unwrap().into(); + alice_conf.conf["log"] = mm_alice.folder.join("mm2_dup.log").to_str().unwrap().into(); + alice_conf.conf["seednodes"] = vec![mm_bob.ip.to_string()].into(); + + let mm_alice = MarketMakerIt::start(alice_conf.conf, alice_conf.rpc_password, None).unwrap(); + let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path); + log!("Alice log path: {}", mm_alice.log_path.display()); + + verify_coins_needed_for_kickstart(&mm_bob, &[ETH, ETH1]); + verify_coins_needed_for_kickstart(&mm_alice, &[ETH, ETH1]); + + enable_coins(&mm_bob, &[ETH, ETH1]); + enable_coins(&mm_alice, &[ETH, ETH1]); + + // give swaps 1 second to restart + thread::sleep(Duration::from_secs(1)); + + verify_active_swaps(&mm_bob, &parsed_uuids); + verify_active_swaps(&mm_alice, &parsed_uuids); + + // coins must be virtually locked after kickstart until swap transactions are sent + verify_locked_amount(&mm_alice, "Taker", ETH1); + verify_locked_amount(&mm_bob, "Maker", ETH); +} + +fn log_swap_status_before_stop(mm: &MarketMakerIt, uuid: &str, role: &str) { + let status = block_on(my_swap_status(mm, uuid)); + log!("{} swap {} status before stop: {:?}", role, uuid, status); +} + +fn verify_coins_needed_for_kickstart(mm: &MarketMakerIt, expected_coins: &[&str]) { + let mut coins_needed = block_on(coins_needed_for_kickstart(mm)); + coins_needed.sort(); + assert_eq!(coins_needed, expected_coins); +} + +fn verify_active_swaps(mm: &MarketMakerIt, expected_uuids: &[Uuid]) { + let active_swaps = block_on(active_swaps(mm)); + assert_eq!(active_swaps.uuids, expected_uuids); +} + +fn verify_locked_amount(mm: &MarketMakerIt, role: &str, coin: &str) { + let locked = block_on(get_locked_amount(mm, coin)); + log!("{} {} locked amount: {:?}", role, coin, locked.locked_amount); + assert_eq!(locked.coin, coin); +} diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 7592384696..6aaee66488 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -820,8 +820,16 @@ pub fn eth_testnet_conf_trezor() -> Json { /// ETH configuration used for dockerized Geth dev node pub fn eth_dev_conf() -> Json { + eth_conf("ETH") +} + +pub fn eth1_dev_conf() -> Json { + eth_conf("ETH1") +} + +fn eth_conf(coin: &str) -> Json { json!({ - "coin": "ETH", + "coin": coin, "name": "ethereum", "mm2": 1, "chain_id": 1337, @@ -2041,6 +2049,51 @@ pub async fn enable_eth_coin( json::from_str(&enable.1).unwrap() } +#[derive(Clone)] +pub struct SwapV2TestContracts { + pub maker_swap_v2_contract: String, + pub taker_swap_v2_contract: String, + pub nft_maker_swap_v2_contract: String, +} + +#[derive(Clone)] +pub struct TestNode { + pub url: String, +} + +pub async fn enable_eth_coin_v2( + mm: &MarketMakerIt, + ticker: &str, + swap_contract_address: &str, + swap_v2_contracts: SwapV2TestContracts, + fallback_swap_contract: Option<&str>, + nodes: &[TestNode], +) -> Json { + let enable = mm + .rpc(&json!({ + "userpass": mm.userpass, + "method": "enable_eth_with_tokens", + "mmrpc": "2.0", + "params": { + "ticker": ticker, + "mm2": 1, + "swap_contract_address": swap_contract_address, + "swap_v2_contracts": { + "maker_swap_v2_contract": swap_v2_contracts.maker_swap_v2_contract, + "taker_swap_v2_contract": swap_v2_contracts.taker_swap_v2_contract, + "nft_maker_swap_v2_contract": swap_v2_contracts.nft_maker_swap_v2_contract + }, + "fallback_swap_contract": fallback_swap_contract, + "nodes": nodes.iter().map(|node| json!({ "url": node.url })).collect::>(), + "erc20_tokens_requests": [] + } + })) + .await + .unwrap(); + assert_eq!(enable.0, StatusCode::OK, "'enable_eth_with_tokens' failed: {}", enable.1); + json::from_str(&enable.1).unwrap() +} + pub async fn enable_slp(mm: &MarketMakerIt, coin: &str) -> Json { let enable = mm .rpc(&json!({