diff --git a/mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs b/mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs index 489d4871b4..023c97653f 100644 --- a/mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs +++ b/mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs @@ -18,7 +18,6 @@ use futures::compat::Future01CompatExt; use mm2_err_handle::mm_error::MmError; use mm2_err_handle::prelude::{MapToMmResult, MmResultExt}; use std::convert::TryInto; -use web3::types::TransactionId; const ETH_MAKER_PAYMENT: &str = "ethMakerPayment"; const ERC20_MAKER_PAYMENT: &str = "erc20MakerPayment"; @@ -122,28 +121,22 @@ impl EthCoin { "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), )); } + let maker_swap_v2_contract = self .swap_v2_contracts .ok_or_else(|| { ValidatePaymentError::InternalError("Expected swap_v2_contracts to be Some, but found None".to_string()) })? .maker_swap_v2_contract; + let taker_secret_hash = args.taker_secret_hash.try_into()?; let maker_secret_hash = args.maker_secret_hash.try_into()?; validate_amount(&args.amount).map_to_mm(ValidatePaymentError::InternalError)?; let swap_id = self.etomic_swap_id_v2(args.time_lock, args.maker_secret_hash); - let tx_from_rpc = self - .transaction(TransactionId::Hash(args.maker_payment_tx.tx_hash())) - .await?; - let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| { - ValidatePaymentError::TxDoesNotExist(format!( - "Didn't find provided tx {:?} on ETH node", - args.maker_payment_tx.tx_hash() - )) - })?; + let tx = args.maker_payment_tx; let maker_address = public_to_address(args.maker_pub); - validate_from_to_addresses(tx_from_rpc, maker_address, maker_swap_v2_contract).map_mm_err()?; + validate_from_to_addresses(tx, maker_address, maker_swap_v2_contract).map_mm_err()?; let validation_args = { let amount = u256_from_big_decimal(&args.amount, self.decimals).map_mm_err()?; @@ -156,15 +149,16 @@ impl EthCoin { payment_time_lock: args.time_lock, } }; + match self.coin_type { EthCoinType::Eth => { let function = MAKER_SWAP_V2.function(ETH_MAKER_PAYMENT)?; - let decoded = decode_contract_call(function, &tx_from_rpc.input.0)?; - validate_eth_maker_payment_data(&decoded, &validation_args, function, tx_from_rpc.value)?; + let decoded = decode_contract_call(function, tx.unsigned().data())?; + validate_eth_maker_payment_data(&decoded, &validation_args, function, tx.unsigned().value())?; }, EthCoinType::Erc20 { token_addr, .. } => { let function = MAKER_SWAP_V2.function(ERC20_MAKER_PAYMENT)?; - let decoded = decode_contract_call(function, &tx_from_rpc.input.0)?; + let decoded = decode_contract_call(function, tx.unsigned().data())?; validate_erc20_maker_payment_data(&decoded, &validation_args, function, token_addr)?; }, EthCoinType::Nft { .. } => { @@ -173,6 +167,8 @@ impl EthCoin { )); }, } + + // Offline checks passed; on-chain confirmation happens later. Ok(()) } diff --git a/mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs b/mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs index 42ca6f4a22..a9120852ca 100644 --- a/mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs +++ b/mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs @@ -3,10 +3,10 @@ use super::{ PaymentMethod, PrepareTxDataError, SpendTxSearchParams, ZERO_VALUE, }; use crate::eth::{ - decode_contract_call, get_function_input_data, u256_from_big_decimal, EthCoin, EthCoinType, ParseCoinAssocTypes, - RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, SignedEthTx, SwapTxTypeWithSecretHash, - TakerPaymentStateV2, TransactionErr, ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, - TAKER_SWAP_V2, + decode_contract_call, get_function_input_data, signed_tx_from_web3_tx, u256_from_big_decimal, EthCoin, EthCoinType, + ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, SignedEthTx, + SwapTxTypeWithSecretHash, TakerPaymentStateV2, TransactionErr, ValidateSwapV2TxError, ValidateSwapV2TxResult, + ValidateTakerFundingArgs, TAKER_SWAP_V2, }; use crate::{ FindPaymentSpendError, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, SearchForFundingSpendErr, @@ -172,7 +172,9 @@ impl EthCoin { )) })?; let taker_address = public_to_address(args.taker_pub); - validate_from_to_addresses(tx_from_rpc, taker_address, taker_swap_v2_contract).map_mm_err()?; + let signed_tx = signed_tx_from_web3_tx(tx_from_rpc.clone()) + .map_err(|err| ValidateSwapV2TxError::WrongPaymentTx(format!("Could not parse tx: {:?}", err)))?; + validate_from_to_addresses(&signed_tx, taker_address, taker_swap_v2_contract).map_mm_err()?; let validation_args = { let dex_fee = u256_from_big_decimal(&args.dex_fee.fee_amount().into(), self.decimals).map_mm_err()?; diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index 0e1eb8ffd2..ad01de3b29 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -1,4 +1,5 @@ use crate::eth::{decode_contract_call, signed_tx_from_web3_tx, EthCoin, EthCoinType, Transaction, TransactionErr}; +use crate::hd_wallet::DisplayAddress; use crate::{FindPaymentSpendError, MarketCoinOps}; use common::executor::Timer; use common::log::{error, info}; @@ -6,13 +7,13 @@ use common::now_sec; use derive_more::Display; use enum_derives::EnumFromStringify; use ethabi::{Contract, Token}; -use ethcore_transaction::SignedTransaction as SignedEthTx; +use ethcore_transaction::{Action, SignedTransaction as SignedEthTx}; use ethereum_types::{Address, H256, U256}; use futures::compat::Future01CompatExt; use mm2_err_handle::prelude::{MmError, MmResult}; use mm2_number::BigDecimal; use num_traits::Signed; -use web3::types::{Transaction as Web3Tx, TransactionId}; +use web3::types::TransactionId; pub(crate) mod eth_maker_swap_v2; pub(crate) mod eth_taker_swap_v2; @@ -175,21 +176,35 @@ impl EthCoin { } pub(crate) fn validate_from_to_addresses( - tx_from_rpc: &Web3Tx, + signed_tx: &SignedEthTx, expected_from: Address, expected_to: Address, ) -> Result<(), MmError> { - if tx_from_rpc.from != Some(expected_from) { + if signed_tx.sender() != expected_from { return MmError::err(ValidatePaymentV2Err::WrongPaymentTx(format!( - "Payment tx {tx_from_rpc:?} was sent from wrong address, expected {expected_from:?}" + "Payment tx {signed_tx:?} was sent from wrong address, expected {}", + expected_from.display_address() ))); } + // (in NFT case) as NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address - if tx_from_rpc.to != Some(expected_to) { - return MmError::err(ValidatePaymentV2Err::WrongPaymentTx(format!( - "Payment tx {tx_from_rpc:?} was sent to wrong address, expected {expected_to:?}", - ))); + match signed_tx.unsigned().action() { + Action::Call(to) => { + if *to != expected_to { + return MmError::err(ValidatePaymentV2Err::WrongPaymentTx(format!( + "Payment tx was sent to wrong address, expected {}, got {}", + expected_to.display_address(), + to.display_address() + ))); + } + }, + Action::Create => { + return MmError::err(ValidatePaymentV2Err::WrongPaymentTx( + "Tx action must be Call, found Create instead".to_string(), + )); + }, } + Ok(()) } diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 24b1687fbd..a55c66a336 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -8,7 +8,7 @@ use mm2_number::BigDecimal; use num_traits::Signed; use web3::types::TransactionId; -use super::ContractType; +use super::{signed_tx_from_web3_tx, ContractType}; use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use crate::eth::eth_swap_v2::{validate_from_to_addresses, PaymentMethod, PrepareTxDataError, ZERO_VALUE}; use crate::eth::{ @@ -92,7 +92,9 @@ impl EthCoin { args.maker_payment_tx.tx_hash() )) })?; - validate_from_to_addresses(tx_from_rpc, maker_address, *token_address).map_mm_err()?; + let signed_tx = signed_tx_from_web3_tx(tx_from_rpc.clone()) + .map_err(|err| ValidatePaymentError::WrongPaymentTx(format!("Could not parse tx: {:?}", err)))?; + validate_from_to_addresses(&signed_tx, maker_address, *token_address).map_mm_err()?; let (decoded, bytes_index) = get_decoded_tx_data_and_bytes_index(contract_type, &tx_from_rpc.input.0)?;