From 81c36d015958b53c6fa329a7a1de1faa7ac5d3bf Mon Sep 17 00:00:00 2001 From: scx1332 Date: Mon, 9 Oct 2023 15:14:00 +0200 Subject: [PATCH] Scx1332/verifiying transactions (#61) Added code for verifying transactions --- crates/erc20_payment_lib/src/config.rs | 2 + crates/erc20_payment_lib/src/runtime.rs | 94 ++++++++++++++++++- .../erc20_payment_lib/src/sender/batching.rs | 72 +++++++------- crates/erc20_payment_lib/src/setup.rs | 2 + .../erc20_payment_lib_test/src/durabily2.rs | 5 +- .../src/multi_erc20_transfer.rs | 6 +- src/main.rs | 3 +- .../docker_01_basic/single_erc20_transfer.rs | 38 +++++--- tests/docker_01_basic/single_gas_transfer.rs | 5 +- tests/docker_02_errors/insufficient_gas.rs | 5 +- tests/docker_02_errors/transfer_stuck.rs | 5 +- .../transfer_stuck_and_replaced.rs | 15 +-- tests/docker_02_errors/wrong_chain_id.rs | 5 +- .../single_transfer_with_problems.rs | 5 +- tests/docker_04_multi.rs | 71 +++++++++++--- 15 files changed, 227 insertions(+), 106 deletions(-) diff --git a/crates/erc20_payment_lib/src/config.rs b/crates/erc20_payment_lib/src/config.rs index cbbe1785..f6f499bd 100644 --- a/crates/erc20_payment_lib/src/config.rs +++ b/crates/erc20_payment_lib/src/config.rs @@ -17,6 +17,7 @@ pub struct AdditionalOptions { pub skip_multi_contract_check: bool, pub contract_use_direct_method: bool, pub contract_use_unpacked_method: bool, + pub use_transfer_for_single_payment: bool, } impl Default for AdditionalOptions { @@ -27,6 +28,7 @@ impl Default for AdditionalOptions { skip_multi_contract_check: false, contract_use_direct_method: false, contract_use_unpacked_method: false, + use_transfer_for_single_payment: true, } } } diff --git a/crates/erc20_payment_lib/src/runtime.rs b/crates/erc20_payment_lib/src/runtime.rs index 557c445f..dfee0547 100644 --- a/crates/erc20_payment_lib/src/runtime.rs +++ b/crates/erc20_payment_lib/src/runtime.rs @@ -3,11 +3,12 @@ use crate::db::ops::{ cleanup_token_transfer_tx, delete_tx, get_last_unsent_tx, insert_token_transfer, }; use crate::signer::Signer; -use crate::transaction::create_token_transfer; +use crate::transaction::{create_token_transfer, find_receipt_extended}; use crate::{err_custom_create, err_from}; use std::collections::BTreeMap; use std::ops::DerefMut; use std::path::Path; +use std::str::FromStr; use crate::error::{ErrorBag, PaymentError}; @@ -27,7 +28,9 @@ use serde::Serialize; use std::sync::Arc; use tokio::sync::Mutex; use tokio::task::JoinHandle; -use web3::types::{Address, U256}; +use web3::transports::Http; +use web3::types::{Address, H256, U256}; +use web3::Web3; #[derive(Debug, Clone, Serialize)] pub struct SharedInfoTx { @@ -373,6 +376,7 @@ impl PaymentRuntime { config.engine.process_sleep, config.engine.automatic_recover, )?; + payment_setup.use_transfer_for_single_payment = options.use_transfer_for_single_payment; payment_setup.extra_options_for_testing = extra_testing; payment_setup.contract_use_direct_method = options.contract_use_direct_method; payment_setup.contract_use_unpacked_method = options.contract_use_unpacked_method; @@ -411,6 +415,17 @@ impl PaymentRuntime { }) } + pub async fn get_web3_provider(&self, chain_name: &str) -> Result, PaymentError> { + let chain_cfg = self.config.chain.get(chain_name).ok_or(err_custom_create!( + "Chain {} not found in config file", + chain_name + ))?; + + let web3 = self.setup.get_provider(chain_cfg.chain_id)?; + + Ok(web3.clone()) + } + pub async fn get_token_balance( &self, chain_name: String, @@ -528,11 +543,86 @@ impl PaymentRuntime { self.get_chain(chain_id).map(|chain| chain.network.as_str()) } + pub async fn verify_transaction( + &self, + chain_id: i64, + tx_hash: H256, + sender: Address, + receiver: Address, + amount: U256, + ) -> Result { + let network_name = self.network_name(chain_id).ok_or(err_custom_create!( + "Chain {} not found in config file", + chain_id + ))?; + let prov = self.get_web3_provider(network_name).await?; + verify_transaction(&prov, chain_id, tx_hash, sender, receiver, amount).await + } + pub fn chains(&self) -> Vec { self.setup.chain_setup.keys().copied().collect() } } +pub struct VerifyTransactionResult { + pub verified: bool, + pub reason: Option, +} + +// This is for now very limited check. It needs lot more work to be complete +pub async fn verify_transaction( + web3: &web3::Web3, + chain_id: i64, + tx_hash: H256, + sender: Address, + receiver: Address, + amount: U256, +) -> Result { + let (chain_tx_dao, transfers) = find_receipt_extended(web3, tx_hash, chain_id).await?; + if chain_tx_dao.chain_status == 1 { + //one transaction can contain multiple transfers. Search for ours. + for transfer in transfers { + log::info!( + "Verifying {tx_hash:#x}: Found transfers on chain: {:?}", + transfer + ); + if Address::from_str(&transfer.receiver_addr).map_err(err_from!())? == receiver + && Address::from_str(&transfer.from_addr).map_err(err_from!())? == sender + { + return if U256::from_dec_str(&transfer.token_amount).map_err(err_from!())? >= amount + { + log::info!("Transaction found and verified: {}", tx_hash); + Ok(VerifyTransactionResult { + verified: true, + reason: None, + }) + } else { + log::warn!( + "Transaction found but amount insufficient: {}: {}/{}", + tx_hash, + transfer.token_amount, + amount + ); + Ok(VerifyTransactionResult { + verified: false, + reason: Some("Transaction found but amount insufficient".to_string()), + }) + }; + } + } + log::warn!("Transaction found but not matching: {}", tx_hash); + Ok(VerifyTransactionResult { + verified: false, + reason: Some("Transaction found but not matching".to_string()), + }) + } else { + Ok(VerifyTransactionResult { + verified: false, + reason: Some("Transaction not found".to_string()), + }) + } +} + pub async fn remove_last_unsent_transactions( conn: SqlitePool, ) -> Result, PaymentError> { diff --git a/crates/erc20_payment_lib/src/sender/batching.rs b/crates/erc20_payment_lib/src/sender/batching.rs index 3a455324..4ac47cf1 100644 --- a/crates/erc20_payment_lib/src/sender/batching.rs +++ b/crates/erc20_payment_lib/src/sender/batching.rs @@ -189,43 +189,41 @@ pub async fn gather_transactions_batch_multi( erc20_amounts.push(sum); } - let web3tx = match erc20_to.len() { - 0 => { - return Ok(0); - } - 1 => { - log::info!( - "Inserting transaction stub for ERC20 transfer to: {:?}", - erc20_to[0] - ); - - create_erc20_transfer( - Address::from_str(&token_transfer.from_addr).map_err(err_from!())?, - Address::from_str(token_addr).map_err(err_from!())?, - erc20_to[0], - erc20_amounts[0], - token_transfer.chain_id as u64, - None, - max_fee_per_gas, - priority_fee, - )? - } - _ => { - log::info!("Inserting transaction stub for ERC20 multi transfer contract: {:?} for {} distinct transfers", chain_setup.multi_contract_address.unwrap(), erc20_to.len()); - - create_erc20_transfer_multi( - Address::from_str(&token_transfer.from_addr).map_err(err_from!())?, - chain_setup.multi_contract_address.unwrap(), - erc20_to, - erc20_amounts, - token_transfer.chain_id as u64, - None, - max_fee_per_gas, - priority_fee, - use_direct_method, - use_unpacked_method, - )? - } + let use_transfer_for_single_payment = false; + + let web3tx = if erc20_to.is_empty() { + return Ok(0); + } else if use_transfer_for_single_payment && erc20_to.len() == 1 { + log::info!( + "Inserting transaction stub for ERC20 transfer to: {:?}", + erc20_to[0] + ); + + create_erc20_transfer( + Address::from_str(&token_transfer.from_addr).map_err(err_from!())?, + Address::from_str(token_addr).map_err(err_from!())?, + erc20_to[0], + erc20_amounts[0], + token_transfer.chain_id as u64, + None, + max_fee_per_gas, + priority_fee, + )? + } else { + log::info!("Inserting transaction stub for ERC20 multi transfer contract: {:?} for {} distinct transfers", chain_setup.multi_contract_address.unwrap(), erc20_to.len()); + + create_erc20_transfer_multi( + Address::from_str(&token_transfer.from_addr).map_err(err_from!())?, + chain_setup.multi_contract_address.unwrap(), + erc20_to, + erc20_amounts, + token_transfer.chain_id as u64, + None, + max_fee_per_gas, + priority_fee, + use_direct_method, + use_unpacked_method, + )? }; let mut db_transaction = conn.begin().await.map_err(err_from!())?; let web3_tx_dao = insert_tx(&mut *db_transaction, &web3tx) diff --git a/crates/erc20_payment_lib/src/setup.rs b/crates/erc20_payment_lib/src/setup.rs index 47831f9d..976b3790 100644 --- a/crates/erc20_payment_lib/src/setup.rs +++ b/crates/erc20_payment_lib/src/setup.rs @@ -64,6 +64,7 @@ pub struct PaymentSetup { pub automatic_recover: bool, pub contract_use_direct_method: bool, pub contract_use_unpacked_method: bool, + pub use_transfer_for_single_payment: bool, pub extra_options_for_testing: Option, } @@ -92,6 +93,7 @@ impl PaymentSetup { contract_use_direct_method: false, contract_use_unpacked_method: false, extra_options_for_testing: None, + use_transfer_for_single_payment: true, }; for chain_config in &config.chain { let mut providers = Vec::new(); diff --git a/crates/erc20_payment_lib_test/src/durabily2.rs b/crates/erc20_payment_lib_test/src/durabily2.rs index d20ce33d..dc19bbcd 100644 --- a/crates/erc20_payment_lib_test/src/durabily2.rs +++ b/crates/erc20_payment_lib_test/src/durabily2.rs @@ -117,10 +117,7 @@ pub async fn test_durability2(generate_count: u64, gen_interval_secs: f64, trans Some(conn_.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), None, diff --git a/crates/erc20_payment_lib_test/src/multi_erc20_transfer.rs b/crates/erc20_payment_lib_test/src/multi_erc20_transfer.rs index 1f412142..812a1656 100644 --- a/crates/erc20_payment_lib_test/src/multi_erc20_transfer.rs +++ b/crates/erc20_payment_lib_test/src/multi_erc20_transfer.rs @@ -117,10 +117,8 @@ pub async fn test_durability(generate_count: u64, gen_interval_secs: f64, transf Some(conn_.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + use_transfer_for_single_payment: false, + ..Default::default() }), Some(sender), None, diff --git a/src/main.rs b/src/main.rs index e72e3af3..1787ac2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -125,8 +125,7 @@ async fn main_internal() -> Result<(), PaymentError> { keep_running: run_options.keep_running, generate_tx_only: run_options.generate_tx_only, skip_multi_contract_check: run_options.skip_multi_contract_check, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }; let sp = PaymentRuntime::new( diff --git a/tests/docker_01_basic/single_erc20_transfer.rs b/tests/docker_01_basic/single_erc20_transfer.rs index 134cc660..ea83dbfa 100644 --- a/tests/docker_01_basic/single_erc20_transfer.rs +++ b/tests/docker_01_basic/single_erc20_transfer.rs @@ -1,8 +1,9 @@ use erc20_payment_lib::config::AdditionalOptions; +use erc20_payment_lib::db::model::TxDao; use erc20_payment_lib::db::ops::insert_token_transfer; use erc20_payment_lib::misc::load_private_keys; use erc20_payment_lib::runtime::DriverEventContent::*; -use erc20_payment_lib::runtime::{DriverEvent, PaymentRuntime}; +use erc20_payment_lib::runtime::{verify_transaction, DriverEvent, PaymentRuntime}; use erc20_payment_lib::signer::PrivateKeySigner; use erc20_payment_lib::transaction::create_token_transfer; use erc20_payment_lib::utils::u256_to_rust_dec; @@ -10,7 +11,7 @@ use erc20_payment_lib_test::*; use rust_decimal::prelude::ToPrimitive; use std::str::FromStr; use std::time::Duration; -use web3::types::{Address, U256}; +use web3::types::{Address, H256, U256}; use web3_test_proxy_client::list_transactions_human; #[tokio::test(flavor = "multi_thread")] @@ -23,6 +24,7 @@ async fn test_erc20_transfer() -> Result<(), anyhow::Error> { let proxy_url_base = format!("http://127.0.0.1:{}", geth_container.web3_proxy_port); let proxy_key = "erc20_transfer"; + let mut tx_dao_return: Option = None; let (sender, mut receiver) = tokio::sync::mpsc::channel::(1); let receiver_loop = tokio::spawn(async move { @@ -42,7 +44,8 @@ async fn test_erc20_transfer() -> Result<(), anyhow::Error> { approve_contract_message_count += 1; fee_paid += U256::from_dec_str(&allowance_dao.fee_paid.expect("fee paid should be set")).expect("fee paid should be a valid U256"); } - TransactionConfirmed(_tx_dao) => { + TransactionConfirmed(tx_dao) => { + tx_dao_return = Some(tx_dao); tx_confirmed_message_count += 1; }, StatusChanged(_) => { } @@ -56,9 +59,9 @@ async fn test_erc20_transfer() -> Result<(), anyhow::Error> { assert_eq!(tx_confirmed_message_count, 2); assert_eq!(transfer_finished_message_count, 1); assert_eq!(approve_contract_message_count, 1); - fee_paid + (fee_paid, tx_dao_return) }); - { + let web3 = { let config = create_default_config_setup(&proxy_url_base, proxy_key).await; //load private key for account 0xbfb29b133aa51c4b45b49468f9a22958eafea6fa @@ -88,20 +91,20 @@ async fn test_erc20_transfer() -> Result<(), anyhow::Error> { Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), None ).await?; + let web3 = sp.get_web3_provider("dev").await.unwrap(); sp.runtime_handle.await?; - } + web3 + }; + #[allow(clippy::bool_assert_comparison)] { // *** RESULT CHECK *** - let fee_paid_u256 = receiver_loop.await.unwrap(); + let (fee_paid_u256, tx_dao) = receiver_loop.await.unwrap(); let fee_paid = u256_to_rust_dec(fee_paid_u256,None).unwrap(); log::info!("fee paid: {}", fee_paid); assert!(fee_paid.to_f64().unwrap() > 0.00008 && fee_paid.to_f64().unwrap() < 0.00015); @@ -118,6 +121,19 @@ async fn test_erc20_transfer() -> Result<(), anyhow::Error> { log::info!("transaction list \n {}", transaction_human.join("\n")); assert!(transaction_human.len() > 30); assert!(transaction_human.len() < 70); + + let tx_dao = tx_dao.unwrap(); + let tx_hash = H256::from_str(&tx_dao.tx_hash.unwrap()).unwrap(); + let fr_str = Address::from_str("0xbfb29b133aa51c4b45b49468f9a22958eafea6fa").unwrap(); + let fr_str_wrong = Address::from_str("0xcfb29b133aa51c4b45b49468f9a22958eafea6fa").unwrap(); + let to_str = Address::from_str("0xf2f86a61b769c91fc78f15059a5bd2c189b84be2").unwrap(); + let to_str_wrong = Address::from_str("0x02f86a61b769c91fc78f15059a5bd2c189b84be2").unwrap(); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str,to_str,U256::from(2222000000000000222_u128)).await.unwrap().verified, true); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str,to_str_wrong,U256::from(2222000000000000222_u128)).await.unwrap().verified, false); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str_wrong,to_str,U256::from(2222000000000000222_u128)).await.unwrap().verified, false); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str,to_str,U256::from(2222000000000000223_u128)).await.unwrap().verified, false); + + } Ok(()) diff --git a/tests/docker_01_basic/single_gas_transfer.rs b/tests/docker_01_basic/single_gas_transfer.rs index e5d2e136..a8cf3560 100644 --- a/tests/docker_01_basic/single_gas_transfer.rs +++ b/tests/docker_01_basic/single_gas_transfer.rs @@ -83,10 +83,7 @@ async fn test_gas_transfer() -> Result<(), anyhow::Error> { Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), None diff --git a/tests/docker_02_errors/insufficient_gas.rs b/tests/docker_02_errors/insufficient_gas.rs index c268ee62..90611b14 100644 --- a/tests/docker_02_errors/insufficient_gas.rs +++ b/tests/docker_02_errors/insufficient_gas.rs @@ -91,10 +91,7 @@ async fn test_insufficient_gas() -> Result<(), anyhow::Error> { Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), None diff --git a/tests/docker_02_errors/transfer_stuck.rs b/tests/docker_02_errors/transfer_stuck.rs index aa9108ce..8d7fd195 100644 --- a/tests/docker_02_errors/transfer_stuck.rs +++ b/tests/docker_02_errors/transfer_stuck.rs @@ -93,10 +93,7 @@ async fn test_transfer_stuck() -> Result<(), anyhow::Error> { Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), None diff --git a/tests/docker_02_errors/transfer_stuck_and_replaced.rs b/tests/docker_02_errors/transfer_stuck_and_replaced.rs index b98da6ca..37c2fa3b 100644 --- a/tests/docker_02_errors/transfer_stuck_and_replaced.rs +++ b/tests/docker_02_errors/transfer_stuck_and_replaced.rs @@ -116,10 +116,7 @@ async fn test_transfer_stuck_and_replaced(scenario: Scenarios) -> Result<(), any Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender.clone()), None @@ -145,10 +142,7 @@ async fn test_transfer_stuck_and_replaced(scenario: Scenarios) -> Result<(), any Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender.clone()), Some(erc20_payment_lib::setup::ExtraOptionsForTesting { @@ -182,10 +176,7 @@ async fn test_transfer_stuck_and_replaced(scenario: Scenarios) -> Result<(), any Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), Some(erc20_payment_lib::setup::ExtraOptionsForTesting { diff --git a/tests/docker_02_errors/wrong_chain_id.rs b/tests/docker_02_errors/wrong_chain_id.rs index 9c2ed888..3381b7ea 100644 --- a/tests/docker_02_errors/wrong_chain_id.rs +++ b/tests/docker_02_errors/wrong_chain_id.rs @@ -98,10 +98,7 @@ async fn test_wrong_chain_id() -> Result<(), anyhow::Error> { Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), None diff --git a/tests/docker_03_problems/single_transfer_with_problems.rs b/tests/docker_03_problems/single_transfer_with_problems.rs index 86bbd85a..ff9a68b3 100644 --- a/tests/docker_03_problems/single_transfer_with_problems.rs +++ b/tests/docker_03_problems/single_transfer_with_problems.rs @@ -140,10 +140,7 @@ async fn test_gas_transfer(error_probability: f64) -> Result<(), anyhow::Error> Some(conn.clone()), Some(AdditionalOptions { keep_running: false, - generate_tx_only: false, - skip_multi_contract_check: false, - contract_use_direct_method: false, - contract_use_unpacked_method: false, + ..Default::default() }), Some(sender), None diff --git a/tests/docker_04_multi.rs b/tests/docker_04_multi.rs index d6e43407..b7a578d7 100644 --- a/tests/docker_04_multi.rs +++ b/tests/docker_04_multi.rs @@ -1,15 +1,16 @@ use erc20_payment_lib::config::AdditionalOptions; +use erc20_payment_lib::db::model::TxDao; use erc20_payment_lib::db::ops::insert_token_transfer; use erc20_payment_lib::misc::load_private_keys; use erc20_payment_lib::runtime::DriverEventContent::*; -use erc20_payment_lib::runtime::{DriverEvent, PaymentRuntime}; +use erc20_payment_lib::runtime::{verify_transaction, DriverEvent, PaymentRuntime}; use erc20_payment_lib::signer::PrivateKeySigner; use erc20_payment_lib::transaction::create_token_transfer; use erc20_payment_lib::utils::u256_to_rust_dec; use erc20_payment_lib_test::*; use std::str::FromStr; use std::time::Duration; -use web3::types::{Address, U256}; +use web3::types::{Address, H256, U256}; use web3_test_proxy_client::list_transactions_human; #[rustfmt::skip] @@ -21,6 +22,7 @@ async fn test_multi_erc20_transfer(payment_count: usize, use_direct_method: bool let proxy_url_base = format!("http://127.0.0.1:{}", geth_container.web3_proxy_port); let proxy_key = "erc20_transfer"; + let mut tx_dao_return: Option = None; let (sender, mut receiver) = tokio::sync::mpsc::channel::(1); let receiver_loop = tokio::spawn(async move { @@ -57,7 +59,7 @@ async fn test_multi_erc20_transfer(payment_count: usize, use_direct_method: bool if tx_dao.method == "MULTI.golemTransferDirect" { tx_transfer_direct_count += 1; } - + tx_dao_return = Some(tx_dao); tx_confirmed_message_count += 1; }, StatusChanged(_) => { } @@ -80,7 +82,7 @@ async fn test_multi_erc20_transfer(payment_count: usize, use_direct_method: bool assert_eq!(tx_confirmed_message_count, 2); assert_eq!(transfer_finished_message_count, payment_count); assert_eq!(approve_contract_message_count, 1); - fee_paid + (fee_paid, tx_dao_return) }); let test_receivers = [ @@ -95,7 +97,7 @@ async fn test_multi_erc20_transfer(payment_count: usize, use_direct_method: bool ("0x0000000000000000000000000000000000000008", 10600000000000000678_u128), ("0x0000000000000000000000000000000000000009", 600000000000000678_u128)]; - { + let web3 = { let config = create_default_config_setup(&proxy_url_base, proxy_key).await; //config.chain.get_mut("dev").unwrap().confirmation_blocks = 0; @@ -133,29 +135,33 @@ async fn test_multi_erc20_transfer(payment_count: usize, use_direct_method: bool skip_multi_contract_check: false, contract_use_direct_method: use_direct_method, contract_use_unpacked_method: use_unpacked_method, + ..Default::default() }), Some(sender), None ).await?; + let web3 = sp.get_web3_provider("dev").await.unwrap(); sp.runtime_handle.await?; - } + web3 + }; + #[allow(clippy::bool_assert_comparison)] { // *** RESULT CHECK *** - let fee_paid = receiver_loop.await.unwrap(); + let (fee_paid, tx_dao) = receiver_loop.await.unwrap(); let fee_paid_decimal = u256_to_rust_dec(fee_paid, None).unwrap(); log::info!("fee paid: {fee_paid_decimal}"); //intersperse is joining strings with separator use itertools::Itertools; #[allow(unstable_name_collisions)] - let res = test_get_balance(&proxy_url_base, - &(test_receivers - .iter() - .take(payment_count) - .map(|el| el.0) - .intersperse(",") - .collect::() + ",0xbfb29b133aa51c4b45b49468f9a22958eafea6fa")) + let res = test_get_balance(&proxy_url_base, + &(test_receivers + .iter() + .take(payment_count) + .map(|el| el.0) + .intersperse(",") + .collect::() + ",0xbfb29b133aa51c4b45b49468f9a22958eafea6fa")) .await.expect("get balance should work"); for (addr, val) in test_receivers.into_iter().take(payment_count) @@ -177,6 +183,20 @@ async fn test_multi_erc20_transfer(payment_count: usize, use_direct_method: bool log::info!("transaction list \n {}", transaction_human.join("\n")); assert!(transaction_human.len() > 30); assert!(transaction_human.len() < 70); + + let tx_dao = tx_dao.unwrap(); + let tx_hash = H256::from_str(&tx_dao.tx_hash.unwrap()).unwrap(); + for (addr, val) in test_receivers.iter().take(payment_count) + { + let fr_str = Address::from_str("0xbfb29b133aa51c4b45b49468f9a22958eafea6fa").unwrap(); + let to_str = Address::from_str(addr).unwrap(); + let fr_str_wrong = Address::from_str("0xcfb29b133aa51c4b45b49468f9a22958eafea6fa").unwrap(); + let to_str_wrong = Address::from_str("0x02f86a61b769c91fc78f15059a5bd2c189b84be2").unwrap(); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str,to_str,U256::from(*val)).await.unwrap().verified, true); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str,to_str_wrong,U256::from(*val)).await.unwrap().verified, false); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str_wrong,to_str,U256::from(*val)).await.unwrap().verified, false); + assert_eq!(verify_transaction(&web3, 987789, tx_hash,fr_str,to_str,U256::from(*val + 1)).await.unwrap().verified, false); + } } Ok(()) @@ -192,6 +212,29 @@ async fn test_multi_erc20_transfer_5() -> Result<(), anyhow::Error> { test_multi_erc20_transfer(5, false, false).await } +#[tokio::test(flavor = "multi_thread")] +async fn test_multi_erc20_transfer_1_indirect_packed() -> Result<(), anyhow::Error> { + test_multi_erc20_transfer(1, false, false).await +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_multi_erc20_transfer_1_direct_unpacked() -> Result<(), anyhow::Error> { + test_multi_erc20_transfer(1, true, true).await?; + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_multi_erc20_transfer_1_direct_packed() -> Result<(), anyhow::Error> { + test_multi_erc20_transfer(1, true, false).await?; + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_multi_erc20_transfer_1_indirect_unpacked() -> Result<(), anyhow::Error> { + test_multi_erc20_transfer(1, false, true).await?; + Ok(()) +} + #[tokio::test(flavor = "multi_thread")] async fn test_multi_erc20_transfer_10_indirect_packed() -> Result<(), anyhow::Error> { test_multi_erc20_transfer(10, false, false).await