From e485de20584b00ab13a24dfdfc0e3c0d8c859ae7 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 20 Aug 2024 18:31:27 +0700 Subject: [PATCH 01/38] create eth_swap_v2 module, and refactor eth_swap_v2.rs to eth_taker_swap_v2.rs --- mm2src/coins/coin_errors.rs | 4 +- .../eth_taker_swap_v2.rs} | 104 ++---------------- mm2src/coins/eth/eth_swap_v2/mod.rs | 99 +++++++++++++++++ mm2src/coins/eth/nft_swap_v2/mod.rs | 4 +- mm2src/coins/lp_coins.rs | 4 +- 5 files changed, 112 insertions(+), 103 deletions(-) rename mm2src/coins/eth/{eth_swap_v2.rs => eth_swap_v2/eth_taker_swap_v2.rs} (90%) create mode 100644 mm2src/coins/eth/eth_swap_v2/mod.rs diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index aead751eb0..2dc9bd2e96 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,5 +1,5 @@ -use crate::eth::eth_swap_v2::{PaymentStatusErr, ValidatePaymentV2Err}; -use crate::eth::nft_swap_v2::errors::{Erc721FunctionError, HtlcParamsError, PrepareTxDataError}; +use crate::eth::eth_swap_v2::{PaymentStatusErr, PrepareTxDataError, ValidatePaymentV2Err}; +use crate::eth::nft_swap_v2::errors::{Erc721FunctionError, HtlcParamsError}; use crate::eth::{EthAssocTypesError, EthNftAssocTypesError, Web3RpcError}; use crate::{utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; use enum_derives::EnumFromStringify; diff --git a/mm2src/coins/eth/eth_swap_v2.rs b/mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs similarity index 90% rename from mm2src/coins/eth/eth_swap_v2.rs rename to mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs index 0d61ac6004..2a09832806 100644 --- a/mm2src/coins/eth/eth_swap_v2.rs +++ b/mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs @@ -1,12 +1,13 @@ -use super::eth::{wei_from_big_decimal, EthCoin, EthCoinType, SignedEthTx, TAKER_SWAP_V2}; -use super::{decode_contract_call, get_function_input_data, ParseCoinAssocTypes, RefundFundingSecretArgs, - RefundTakerPaymentArgs, SendTakerFundingArgs, SwapTxTypeWithSecretHash, TakerPaymentStateV2, Transaction, - TransactionErr, ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs}; +use super::{validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentStatusErr, PrepareTxDataError, + ZERO_VALUE}; +use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, + ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, + SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, Transaction, TransactionErr, + ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; use crate::{FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, SearchForFundingSpendErr, WaitForTakerPaymentSpendError}; use common::executor::Timer; use common::now_sec; -use enum_derives::EnumFromStringify; use ethabi::{Contract, Function, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, Public, U256}; @@ -15,13 +16,8 @@ use futures::compat::Future01CompatExt; use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; use mm2_number::BigDecimal; use std::convert::TryInto; -use web3::types::{Transaction as Web3Tx, TransactionId}; +use web3::types::TransactionId; -/// ZERO_VALUE is used to represent a 0 amount in transactions where the value is encoded in the transaction input data. -/// This is typically used in function calls where the value is not directly transferred with the transaction, such as in -/// `spendTakerPayment` where the [amount](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L166) -/// is provided as part of the input data rather than as an Ether value -pub(crate) const ZERO_VALUE: u32 = 0; const ETH_TAKER_PAYMENT: &str = "ethTakerPayment"; const ERC20_TAKER_PAYMENT: &str = "erc20TakerPayment"; const TAKER_PAYMENT_APPROVE: &str = "takerPaymentApprove"; @@ -726,15 +722,6 @@ impl EthCoin { } } -#[derive(Debug, Display, EnumFromStringify)] -pub(crate) enum PrepareTxDataError { - #[from_stringify("ethabi::Error")] - #[display(fmt = "ABI error: {}", _0)] - ABIError(String), - #[display(fmt = "Internal error: {}", _0)] - Internal(String), -} - // TODO validate premium when add its support in swap_v2 fn validate_payment_args<'a>( taker_secret_hash: &'a [u8], @@ -757,35 +744,6 @@ fn validate_payment_args<'a>( #[inline(always)] fn is_positive(amount: &BigDecimal) -> bool { amount > &BigDecimal::from(0) } -pub(crate) fn validate_from_to_and_status( - tx_from_rpc: &Web3Tx, - expected_from: Address, - expected_to: Address, - status: U256, - expected_status: u8, -) -> Result<(), MmError> { - if status != U256::from(expected_status) { - return MmError::err(ValidatePaymentV2Err::UnexpectedPaymentState(format!( - "Payment state is not `PaymentSent`, got {}", - status - ))); - } - if tx_from_rpc.from != Some(expected_from) { - return MmError::err(ValidatePaymentV2Err::WrongPaymentTx(format!( - "Payment tx {:?} was sent from wrong address, expected {:?}", - tx_from_rpc, expected_from - ))); - } - // (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 {:?} was sent to wrong address, expected {:?}", - tx_from_rpc, expected_to, - ))); - } - Ok(()) -} - struct TakerValidationArgs<'a> { swap_id: Vec, amount: U256, @@ -870,54 +828,6 @@ fn validate_erc20_taker_payment_data( Ok(()) } -pub(crate) fn validate_payment_state( - tx: &SignedEthTx, - state: U256, - expected_state: u8, -) -> Result<(), PrepareTxDataError> { - if state != U256::from(expected_state) { - return Err(PrepareTxDataError::Internal(format!( - "Payment {:?} state is not `{}`, got `{}`", - tx, expected_state, state - ))); - } - Ok(()) -} - -#[derive(Debug, Display)] -pub(crate) enum ValidatePaymentV2Err { - UnexpectedPaymentState(String), - WrongPaymentTx(String), -} - -pub(crate) enum EthPaymentType { - MakerPayments, - TakerPayments, -} - -impl EthPaymentType { - pub(crate) fn as_str(&self) -> &'static str { - match self { - EthPaymentType::MakerPayments => "makerPayments", - EthPaymentType::TakerPayments => "takerPayments", - } - } -} - -#[derive(Debug, Display, EnumFromStringify)] -pub(crate) enum PaymentStatusErr { - #[from_stringify("ethabi::Error")] - #[display(fmt = "ABI error: {}", _0)] - ABIError(String), - #[from_stringify("web3::Error")] - #[display(fmt = "Transport error: {}", _0)] - Transport(String), - #[display(fmt = "Internal error: {}", _0)] - Internal(String), - #[display(fmt = "Invalid data error: {}", _0)] - InvalidData(String), -} - fn check_decoded_length(decoded: &Vec, expected_len: usize) -> Result<(), PrepareTxDataError> { if decoded.len() != expected_len { return Err(PrepareTxDataError::Internal(format!( diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs new file mode 100644 index 0000000000..b4c11798ba --- /dev/null +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -0,0 +1,99 @@ +use enum_derives::EnumFromStringify; +use ethcore_transaction::SignedTransaction as SignedEthTx; +use ethereum_types::{Address, U256}; +use mm2_err_handle::mm_error::MmError; +use web3::types::Transaction as Web3Tx; + +pub(crate) mod eth_taker_swap_v2; + +/// ZERO_VALUE is used to represent a 0 amount in transactions where the value is encoded in the transaction input data. +/// This is typically used in function calls where the value is not directly transferred with the transaction, such as in +/// `spendTakerPayment` where the [amount](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L166) +/// is provided as part of the input data rather than as an Ether value +pub(crate) const ZERO_VALUE: u32 = 0; + +pub(crate) enum EthPaymentType { + MakerPayments, + TakerPayments, +} + +impl EthPaymentType { + pub(crate) fn as_str(&self) -> &'static str { + match self { + EthPaymentType::MakerPayments => "makerPayments", + EthPaymentType::TakerPayments => "takerPayments", + } + } +} + +#[derive(Debug, Display)] +pub(crate) enum ValidatePaymentV2Err { + UnexpectedPaymentState(String), + WrongPaymentTx(String), +} + +#[derive(Debug, Display, EnumFromStringify)] +pub(crate) enum PaymentStatusErr { + #[from_stringify("ethabi::Error")] + #[display(fmt = "ABI error: {}", _0)] + ABIError(String), + #[from_stringify("web3::Error")] + #[display(fmt = "Transport error: {}", _0)] + Transport(String), + #[display(fmt = "Internal error: {}", _0)] + Internal(String), + #[display(fmt = "Invalid data error: {}", _0)] + InvalidData(String), +} + +#[derive(Debug, Display, EnumFromStringify)] +pub(crate) enum PrepareTxDataError { + #[from_stringify("ethabi::Error")] + #[display(fmt = "ABI error: {}", _0)] + ABIError(String), + #[display(fmt = "Internal error: {}", _0)] + Internal(String), +} + +pub(crate) fn validate_payment_state( + tx: &SignedEthTx, + state: U256, + expected_state: u8, +) -> Result<(), PrepareTxDataError> { + if state != U256::from(expected_state) { + return Err(PrepareTxDataError::Internal(format!( + "Payment {:?} state is not `{}`, got `{}`", + tx, expected_state, state + ))); + } + Ok(()) +} + +pub(crate) fn validate_from_to_and_status( + tx_from_rpc: &Web3Tx, + expected_from: Address, + expected_to: Address, + status: U256, + expected_status: u8, +) -> Result<(), MmError> { + if status != U256::from(expected_status) { + return MmError::err(ValidatePaymentV2Err::UnexpectedPaymentState(format!( + "Payment state is not `PaymentSent`, got {}", + status + ))); + } + if tx_from_rpc.from != Some(expected_from) { + return MmError::err(ValidatePaymentV2Err::WrongPaymentTx(format!( + "Payment tx {:?} was sent from wrong address, expected {:?}", + tx_from_rpc, expected_from + ))); + } + // (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 {:?} was sent to wrong address, expected {:?}", + tx_from_rpc, expected_to, + ))); + } + Ok(()) +} diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index d5de6dcc86..6f6a8965fd 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -9,13 +9,13 @@ use mm2_number::BigDecimal; use web3::types::TransactionId; pub(crate) mod errors; -use errors::{Erc721FunctionError, HtlcParamsError, PrepareTxDataError}; +use errors::{Erc721FunctionError, HtlcParamsError}; mod structs; use structs::{ExpectedHtlcParams, ValidationParams}; use super::ContractType; use crate::eth::eth_swap_v2::{validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentStatusErr, - ZERO_VALUE}; + PrepareTxDataError, ZERO_VALUE}; use crate::eth::{decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, ERC1155_CONTRACT, ERC721_CONTRACT, NFT_MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundNftMakerPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 8ca714a34f..73fd6db91e 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -240,7 +240,6 @@ use coin_errors::{MyAddressError, ValidatePaymentError, ValidatePaymentFut, Vali pub mod coins_tests; pub mod eth; -use eth::eth_swap_v2::{PaymentStatusErr, ValidatePaymentV2Err}; use eth::GetValidEthWithdrawAddError; use eth::{eth_coin_from_conf_and_request, get_eth_address, EthCoin, EthGasDetailsErr, EthTxFeeDetails, GetEthAddressError, SignedEthTx}; @@ -320,7 +319,8 @@ pub mod z_coin; use crate::coin_balance::{BalanceObjectOps, HDWalletBalanceObject}; use z_coin::{ZCoin, ZcoinProtocolInfo}; #[cfg(feature = "enable-sia")] pub mod sia; -use crate::eth::eth_swap_v2::PrepareTxDataError; +use eth::eth_swap_v2::PrepareTxDataError; +use eth::eth_swap_v2::{PaymentStatusErr, ValidatePaymentV2Err}; #[cfg(feature = "enable-sia")] use sia::SiaCoin; pub type TransactionFut = Box + Send>; From 6593dc7e3e45480f9b4a2035aae81ed1409f4715 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 28 Aug 2024 08:59:21 +0700 Subject: [PATCH 02/38] maker ops: send_maker_payment_v2_impl added --- mm2src/coins/eth.rs | 29 ++++ .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 160 ++++++++++++++++++ mm2src/coins/eth/eth_swap_v2/mod.rs | 1 + 3 files changed, 190 insertions(+) create mode 100644 mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index a6cd170627..e95e6b9d21 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -7218,3 +7218,32 @@ impl EthCoin { EthCoin(Arc::new(coin)) } } + +#[async_trait] +impl MakerCoinSwapOpsV2 for EthCoin { + async fn send_maker_payment_v2(&self, args: SendMakerPaymentArgs<'_, Self>) -> Result { + self.send_maker_payment_v2_impl(args).await + } + + async fn validate_maker_payment_v2(&self, args: ValidateMakerPaymentArgs<'_, Self>) -> ValidatePaymentResult<()> { + self.validate_maker_payment_v2_impl(args).await + } + + async fn refund_maker_payment_v2_timelock( + &self, + args: RefundMakerPaymentTimelockArgs<'_>, + ) -> Result { + self.refund_maker_payment_v2_timelock_impl(args).await + } + + async fn refund_maker_payment_v2_secret( + &self, + args: RefundMakerPaymentSecretArgs<'_, Self>, + ) -> Result { + self.refund_maker_payment_v2_secret_impl(args).await + } + + async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result { + self.spend_maker_payment_v2_impl(args).await + } +} 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 new file mode 100644 index 0000000000..a5334c878e --- /dev/null +++ b/mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs @@ -0,0 +1,160 @@ +use crate::coin_errors::ValidatePaymentResult; +use crate::eth::eth_swap_v2::{PrepareTxDataError, ZERO_VALUE}; +use crate::eth::{wei_from_big_decimal, EthCoin, EthCoinType, SignedEthTx, TAKER_SWAP_V2}; +use crate::{RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, SpendMakerPaymentArgs, + Transaction, TransactionErr, ValidateMakerPaymentArgs}; +use ethabi::Token; +use ethcore_transaction::Action; +use ethereum_types::{Address, U256}; +use ethkey::public_to_address; +use futures::compat::Future01CompatExt; +use std::convert::TryInto; + +const ETH_MAKER_PAYMENT: &str = "ethMakerPayment"; +const ERC20_MAKER_PAYMENT: &str = "erc20MakerPayment"; + +struct MakerPaymentArgs { + taker_address: Address, + taker_secret_hash: [u8; 32], + maker_secret_hash: [u8; 32], + payment_time_lock: u64, +} + +impl EthCoin { + pub(crate) async fn send_maker_payment_v2_impl( + &self, + args: SendMakerPaymentArgs<'_, Self>, + ) -> Result { + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); + let payment_args = { + let taker_address = public_to_address(args.taker_pub); + MakerPaymentArgs { + taker_address, + taker_secret_hash: try_tx_s!(args.taker_secret_hash.try_into()), + maker_secret_hash: try_tx_s!(args.maker_secret_hash.try_into()), + payment_time_lock: args.time_lock, + } + }; + match &self.coin_type { + EthCoinType::Eth => { + let data = try_tx_s!(self.prepare_maker_eth_payment_data(&payment_args).await); + self.sign_and_send_transaction( + payment_amount, + Action::Call(maker_swap_v2_contract), + data, + // TODO need new consts and params for v2 calls. now it uses v1 + U256::from(self.gas_limit.eth_payment), + ) + .compat() + .await + }, + EthCoinType::Erc20 { + platform: _, + token_addr, + } => { + let allowed = self + .allowance(maker_swap_v2_contract) + .compat() + .await + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let data = try_tx_s!( + self.prepare_maker_erc20_payment_data(&payment_args, payment_amount, *token_addr) + .await + ); + if allowed < payment_amount { + let approved_tx = self.approve(maker_swap_v2_contract, U256::max_value()).compat().await?; + self.wait_for_required_allowance(maker_swap_v2_contract, payment_amount, args.time_lock) + .compat() + .await + .map_err(|e| { + TransactionErr::Plain(ERRL!( + "Allowed value was not updated in time after sending approve transaction {:02x}: {}", + approved_tx.tx_hash_as_bytes(), + e + )) + })?; + } + self.sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(maker_swap_v2_contract), + data, + // TODO need new consts and params for v2 calls. now it uses v1 + U256::from(self.gas_limit.erc20_payment), + ) + .compat() + .await + }, + EthCoinType::Nft { .. } => Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))), + } + } + + pub(crate) async fn validate_maker_payment_v2_impl( + &self, + _args: ValidateMakerPaymentArgs<'_, Self>, + ) -> ValidatePaymentResult<()> { + todo!() + } + + pub(crate) async fn refund_maker_payment_v2_timelock_impl( + &self, + _args: RefundMakerPaymentTimelockArgs<'_>, + ) -> Result { + todo!() + } + + pub(crate) async fn refund_maker_payment_v2_secret_impl( + &self, + _args: RefundMakerPaymentSecretArgs<'_, Self>, + ) -> Result { + todo!() + } + + pub(crate) async fn spend_maker_payment_v2_impl( + &self, + _args: SpendMakerPaymentArgs<'_, Self>, + ) -> Result { + todo!() + } + + /// Prepares data for EtomicSwapMakerV2 contract [ethMakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L30) method + async fn prepare_maker_eth_payment_data(&self, args: &MakerPaymentArgs) -> Result, PrepareTxDataError> { + let function = TAKER_SWAP_V2.function(ETH_MAKER_PAYMENT)?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); + let data = function.encode_input(&[ + Token::FixedBytes(id), + Token::Address(args.taker_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Uint(args.payment_time_lock.into()), + ])?; + Ok(data) + } + + /// Prepares data for EtomicSwapMakerV2 contract [erc20MakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L64) method + async fn prepare_maker_erc20_payment_data( + &self, + args: &MakerPaymentArgs, + payment_amount: U256, + token_address: Address, + ) -> Result, PrepareTxDataError> { + let function = TAKER_SWAP_V2.function(ERC20_MAKER_PAYMENT)?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); + let data = function.encode_input(&[ + Token::FixedBytes(id), + Token::Uint(payment_amount), + Token::Address(token_address), + Token::Address(args.taker_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Uint(args.payment_time_lock.into()), + ])?; + Ok(data) + } +} diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index b4c11798ba..a666ba7f6e 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -4,6 +4,7 @@ use ethereum_types::{Address, U256}; use mm2_err_handle::mm_error::MmError; use web3::types::Transaction as Web3Tx; +pub(crate) mod eth_maker_swap_v2; pub(crate) mod eth_taker_swap_v2; /// ZERO_VALUE is used to represent a 0 amount in transactions where the value is encoded in the transaction input data. From 9eac0fd683aa0e0ac0bb9a6e17d8cbef0ee91d39 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 30 Aug 2024 17:53:44 +0700 Subject: [PATCH 03/38] WIP: validate_maker_payment_v2_impl --- mm2src/coins/coin_errors.rs | 7 ++- mm2src/coins/eth.rs | 26 ++++++-- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 60 ++++++++++++++++-- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 61 +------------------ mm2src/coins/eth/eth_swap_v2/mod.rs | 60 ++++++++++++++++++ 5 files changed, 142 insertions(+), 72 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 2dc9bd2e96..707866e552 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -49,8 +49,7 @@ pub enum ValidatePaymentError { WatcherRewardError(String), /// Input payment timelock overflows the type used by specific coin. TimelockOverflow(TryFromIntError), - #[display(fmt = "Nft Protocol is not supported yet!")] - NftProtocolNotSupported, + ProtocolNotSupported(String), InvalidData(String), } @@ -77,7 +76,9 @@ impl From for ValidatePaymentError { | Web3RpcError::Timeout(internal) | Web3RpcError::NumConversError(internal) | Web3RpcError::InvalidGasApiConfig(internal) => ValidatePaymentError::InternalError(internal), - Web3RpcError::NftProtocolNotSupported => ValidatePaymentError::NftProtocolNotSupported, + Web3RpcError::NftProtocolNotSupported => { + ValidatePaymentError::ProtocolNotSupported("Nft protocol is not supported".to_string()) + }, } } } diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index e95e6b9d21..98cf5c7829 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -1759,7 +1759,11 @@ impl WatcherOps for EthCoin { ))); } }, - EthCoinType::Nft { .. } => return MmError::err(ValidatePaymentError::NftProtocolNotSupported), + EthCoinType::Nft { .. } => { + return MmError::err(ValidatePaymentError::ProtocolNotSupported( + "Nft protocol is not supported by watchers yet".to_string(), + )) + }, } Ok(()) @@ -2000,7 +2004,11 @@ impl WatcherOps for EthCoin { ))); } }, - EthCoinType::Nft { .. } => return MmError::err(ValidatePaymentError::NftProtocolNotSupported), + EthCoinType::Nft { .. } => { + return MmError::err(ValidatePaymentError::ProtocolNotSupported( + "Nft protocol is not supported by watchers yet".to_string(), + )) + }, } Ok(()) @@ -4612,7 +4620,7 @@ impl EthCoin { EthCoinType::Erc20 { token_addr, .. } => token_addr, EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( - "Nft Protocol is not supported yet!" + "Nft Protocol is not supported by 'approve'!" ))) }, }; @@ -4952,7 +4960,11 @@ impl EthCoin { ))); } }, - EthCoinType::Nft { .. } => return MmError::err(ValidatePaymentError::NftProtocolNotSupported), + EthCoinType::Nft { .. } => { + return MmError::err(ValidatePaymentError::ProtocolNotSupported( + "Nft protocol is not supported by legacy swap".to_string(), + )) + }, } Ok(()) @@ -5890,7 +5902,11 @@ fn validate_fee_impl(coin: EthCoin, validate_fee_args: EthValidateFeeArgs<'_>) - }, } }, - EthCoinType::Nft { .. } => return MmError::err(ValidatePaymentError::NftProtocolNotSupported), + EthCoinType::Nft { .. } => { + return MmError::err(ValidatePaymentError::ProtocolNotSupported( + "Nft protocol is not supported".to_string(), + )) + }, } Ok(()) 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 a5334c878e..66a2d4849e 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 @@ -1,6 +1,6 @@ -use crate::coin_errors::ValidatePaymentResult; -use crate::eth::eth_swap_v2::{PrepareTxDataError, ZERO_VALUE}; -use crate::eth::{wei_from_big_decimal, EthCoin, EthCoinType, SignedEthTx, TAKER_SWAP_V2}; +use super::{validate_payment_args, EthPaymentType, PrepareTxDataError, ZERO_VALUE}; +use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; +use crate::eth::{wei_from_big_decimal, EthCoin, EthCoinType, SignedEthTx, MAKER_SWAP_V2}; use crate::{RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, SpendMakerPaymentArgs, Transaction, TransactionErr, ValidateMakerPaymentArgs}; use ethabi::Token; @@ -8,7 +8,10 @@ use ethcore_transaction::Action; use ethereum_types::{Address, U256}; use ethkey::public_to_address; use futures::compat::Future01CompatExt; +use mm2_err_handle::mm_error::MmError; +use mm2_err_handle::prelude::MapToMmResult; use std::convert::TryInto; +use web3::types::TransactionId; const ETH_MAKER_PAYMENT: &str = "ethMakerPayment"; const ERC20_MAKER_PAYMENT: &str = "erc20MakerPayment"; @@ -20,6 +23,16 @@ struct MakerPaymentArgs { payment_time_lock: u64, } +#[allow(dead_code)] +struct MakerValidationArgs<'a> { + swap_id: Vec, + amount: U256, + taker: Address, + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + payment_time_lock: u64, +} + impl EthCoin { pub(crate) async fn send_maker_payment_v2_impl( &self, @@ -97,8 +110,43 @@ impl EthCoin { pub(crate) async fn validate_maker_payment_v2_impl( &self, - _args: ValidateMakerPaymentArgs<'_, Self>, + args: ValidateMakerPaymentArgs<'_, Self>, ) -> ValidatePaymentResult<()> { + if let EthCoinType::Nft { .. } = self.coin_type { + return MmError::err(ValidatePaymentError::ProtocolNotSupported( + "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), + )); + } + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| { + ValidatePaymentError::InternalError("Expected swap_v2_contracts to be Some, but found None".to_string()) + })?; + validate_payment_args(args.taker_secret_hash, args.maker_secret_hash, &args.amount) + .map_to_mm(ValidatePaymentError::InternalError)?; + let _maker_address = public_to_address(args.maker_pub); + let swap_id = self.etomic_swap_id_v2(args.time_lock, args.maker_secret_hash); + let _maker_status = self + .payment_status_v2( + maker_swap_v2_contract, + Token::FixedBytes(swap_id.clone()), + &MAKER_SWAP_V2, + EthPaymentType::MakerPayments, + 2, + ) + .await?; + + 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() + )) + })?; todo!() } @@ -125,7 +173,7 @@ impl EthCoin { /// Prepares data for EtomicSwapMakerV2 contract [ethMakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L30) method async fn prepare_maker_eth_payment_data(&self, args: &MakerPaymentArgs) -> Result, PrepareTxDataError> { - let function = TAKER_SWAP_V2.function(ETH_MAKER_PAYMENT)?; + let function = MAKER_SWAP_V2.function(ETH_MAKER_PAYMENT)?; let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); let data = function.encode_input(&[ Token::FixedBytes(id), @@ -144,7 +192,7 @@ impl EthCoin { payment_amount: U256, token_address: Address, ) -> Result, PrepareTxDataError> { - let function = TAKER_SWAP_V2.function(ERC20_MAKER_PAYMENT)?; + let function = MAKER_SWAP_V2.function(ERC20_MAKER_PAYMENT)?; let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); let data = function.encode_input(&[ Token::FixedBytes(id), 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 2a09832806..2583d6ffb5 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 @@ -1,5 +1,5 @@ -use super::{validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentStatusErr, PrepareTxDataError, - ZERO_VALUE}; +use super::{validate_from_to_and_status, validate_payment_args, validate_payment_state, EthPaymentType, + PrepareTxDataError, ZERO_VALUE}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, Transaction, TransactionErr, @@ -8,13 +8,12 @@ use crate::{FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, WaitForTakerPaymentSpendError}; use common::executor::Timer; use common::now_sec; -use ethabi::{Contract, Function, Token}; +use ethabi::{Function, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, Public, U256}; use ethkey::public_to_address; use futures::compat::Future01CompatExt; use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; -use mm2_number::BigDecimal; use std::convert::TryInto; use web3::types::TransactionId; @@ -636,38 +635,6 @@ impl EthCoin { Ok(data) } - /// Retrieves the payment status from a given smart contract address based on the swap ID and state type. - pub(crate) async fn payment_status_v2( - &self, - swap_address: Address, - swap_id: Token, - contract_abi: &Contract, - payment_type: EthPaymentType, - state_index: usize, - ) -> Result { - let function_name = payment_type.as_str(); - let function = contract_abi.function(function_name)?; - let data = function.encode_input(&[swap_id])?; - let bytes = self - .call_request(self.my_addr().await, swap_address, None, Some(data.into())) - .await?; - let decoded_tokens = function.decode_output(&bytes.0)?; - - let state = decoded_tokens.get(state_index).ok_or_else(|| { - PaymentStatusErr::Internal(format!( - "Payment status must contain 'state' as the {} token", - state_index - )) - })?; - match state { - Token::Uint(state) => Ok(*state), - _ => Err(PaymentStatusErr::InvalidData(format!( - "Payment status must be Uint, got {:?}", - state - ))), - } - } - /// Retrieves the taker smart contract address, the corresponding function, and the token address. /// /// Depending on the coin type (ETH or ERC20), it fetches the appropriate function name and token address. @@ -722,28 +689,6 @@ impl EthCoin { } } -// TODO validate premium when add its support in swap_v2 -fn validate_payment_args<'a>( - taker_secret_hash: &'a [u8], - maker_secret_hash: &'a [u8], - trading_amount: &BigDecimal, -) -> Result<(), String> { - if !is_positive(trading_amount) { - return Err("trading_amount must be a positive value".to_string()); - } - if taker_secret_hash.len() != 32 { - return Err("taker_secret_hash must be 32 bytes".to_string()); - } - if maker_secret_hash.len() != 32 { - return Err("maker_secret_hash must be 32 bytes".to_string()); - } - Ok(()) -} - -/// function to check if BigDecimal is a positive value -#[inline(always)] -fn is_positive(amount: &BigDecimal) -> bool { amount > &BigDecimal::from(0) } - struct TakerValidationArgs<'a> { swap_id: Vec, amount: U256, diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index a666ba7f6e..1a3c62307e 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -1,7 +1,11 @@ +use crate::eth::EthCoin; +use crate::ParseCoinAssocTypes; use enum_derives::EnumFromStringify; +use ethabi::{Contract, Token}; use ethcore_transaction::SignedTransaction as SignedEthTx; use ethereum_types::{Address, U256}; use mm2_err_handle::mm_error::MmError; +use mm2_number::BigDecimal; use web3::types::Transaction as Web3Tx; pub(crate) mod eth_maker_swap_v2; @@ -56,6 +60,40 @@ pub(crate) enum PrepareTxDataError { Internal(String), } +impl EthCoin { + /// Retrieves the payment status from a given smart contract address based on the swap ID and state type. + pub(crate) async fn payment_status_v2( + &self, + swap_address: Address, + swap_id: Token, + contract_abi: &Contract, + payment_type: EthPaymentType, + state_index: usize, + ) -> Result { + let function_name = payment_type.as_str(); + let function = contract_abi.function(function_name)?; + let data = function.encode_input(&[swap_id])?; + let bytes = self + .call_request(self.my_addr().await, swap_address, None, Some(data.into())) + .await?; + let decoded_tokens = function.decode_output(&bytes.0)?; + + let state = decoded_tokens.get(state_index).ok_or_else(|| { + PaymentStatusErr::Internal(format!( + "Payment status must contain 'state' as the {} token", + state_index + )) + })?; + match state { + Token::Uint(state) => Ok(*state), + _ => Err(PaymentStatusErr::InvalidData(format!( + "Payment status must be Uint, got {:?}", + state + ))), + } + } +} + pub(crate) fn validate_payment_state( tx: &SignedEthTx, state: U256, @@ -98,3 +136,25 @@ pub(crate) fn validate_from_to_and_status( } Ok(()) } + +/// function to check if BigDecimal is a positive value +#[inline(always)] +fn is_positive(amount: &BigDecimal) -> bool { amount > &BigDecimal::from(0) } + +// TODO validate premium when add its support in swap_v2 +pub(crate) fn validate_payment_args<'a>( + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + trading_amount: &BigDecimal, +) -> Result<(), String> { + if !is_positive(trading_amount) { + return Err("trading_amount must be a positive value".to_string()); + } + if taker_secret_hash.len() != 32 { + return Err("taker_secret_hash must be 32 bytes".to_string()); + } + if maker_secret_hash.len() != 32 { + return Err("maker_secret_hash must be 32 bytes".to_string()); + } + Ok(()) +} From 4fc3971ecaf701b31198c7ead46f6db77d92f5ce Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 30 Aug 2024 18:13:03 +0700 Subject: [PATCH 04/38] remove unused import --- mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs | 15 ++------------- mm2src/coins/eth/eth_swap_v2/mod.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 14 deletions(-) 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 2583d6ffb5..cccf6b96d1 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 @@ -1,5 +1,5 @@ -use super::{validate_from_to_and_status, validate_payment_args, validate_payment_state, EthPaymentType, - PrepareTxDataError, ZERO_VALUE}; +use super::{check_decoded_length, validate_from_to_and_status, validate_payment_args, validate_payment_state, + EthPaymentType, PrepareTxDataError, ZERO_VALUE}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, Transaction, TransactionErr, @@ -772,14 +772,3 @@ fn validate_erc20_taker_payment_data( } Ok(()) } - -fn check_decoded_length(decoded: &Vec, expected_len: usize) -> Result<(), PrepareTxDataError> { - if decoded.len() != expected_len { - return Err(PrepareTxDataError::Internal(format!( - "Invalid number of tokens in decoded. Expected {}, found {}", - expected_len, - decoded.len() - ))); - } - Ok(()) -} diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index 1a3c62307e..52e2137a93 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -142,7 +142,7 @@ pub(crate) fn validate_from_to_and_status( fn is_positive(amount: &BigDecimal) -> bool { amount > &BigDecimal::from(0) } // TODO validate premium when add its support in swap_v2 -pub(crate) fn validate_payment_args<'a>( +fn validate_payment_args<'a>( taker_secret_hash: &'a [u8], maker_secret_hash: &'a [u8], trading_amount: &BigDecimal, @@ -158,3 +158,14 @@ pub(crate) fn validate_payment_args<'a>( } Ok(()) } + +fn check_decoded_length(decoded: &Vec, expected_len: usize) -> Result<(), PrepareTxDataError> { + if decoded.len() != expected_len { + return Err(PrepareTxDataError::Internal(format!( + "Invalid number of tokens in decoded. Expected {}, found {}", + expected_len, + decoded.len() + ))); + } + Ok(()) +} From 45d472672c3479ad4e1845d9c3bcd46eaabe2821 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 30 Aug 2024 21:55:08 +0700 Subject: [PATCH 05/38] maker tpu v2: validate_maker_payment_v2_impl --- mm2src/coins/coin_errors.rs | 3 +- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 118 ++++++++++++++++-- 2 files changed, 110 insertions(+), 11 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 707866e552..90e9fe413b 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -24,7 +24,8 @@ pub enum ValidatePaymentError { "NumConversError", "UnexpectedDerivationMethod", "keys::Error", - "PrepareTxDataError" + "PrepareTxDataError", + "ethabi::Error" )] InternalError(String), /// Problem with deserializing the transaction, or one of the transaction parts is invalid. 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 66a2d4849e..00487848b5 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 @@ -1,9 +1,10 @@ -use super::{validate_payment_args, EthPaymentType, PrepareTxDataError, ZERO_VALUE}; +use super::{validate_from_to_and_status, validate_payment_args, EthPaymentType, PrepareTxDataError, ZERO_VALUE}; use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; -use crate::eth::{wei_from_big_decimal, EthCoin, EthCoinType, SignedEthTx, MAKER_SWAP_V2}; -use crate::{RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, SpendMakerPaymentArgs, - Transaction, TransactionErr, ValidateMakerPaymentArgs}; -use ethabi::Token; +use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, + MakerPaymentStateV2, SignedEthTx, MAKER_SWAP_V2}; +use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, + SpendMakerPaymentArgs, Transaction, TransactionErr, ValidateMakerPaymentArgs}; +use ethabi::{Function, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, U256}; use ethkey::public_to_address; @@ -23,7 +24,6 @@ struct MakerPaymentArgs { payment_time_lock: u64, } -#[allow(dead_code)] struct MakerValidationArgs<'a> { swap_id: Vec, amount: U256, @@ -126,9 +126,9 @@ impl EthCoin { })?; validate_payment_args(args.taker_secret_hash, args.maker_secret_hash, &args.amount) .map_to_mm(ValidatePaymentError::InternalError)?; - let _maker_address = public_to_address(args.maker_pub); + let maker_address = public_to_address(args.maker_pub); let swap_id = self.etomic_swap_id_v2(args.time_lock, args.maker_secret_hash); - let _maker_status = self + let maker_status = self .payment_status_v2( maker_swap_v2_contract, Token::FixedBytes(swap_id.clone()), @@ -141,13 +141,45 @@ impl EthCoin { 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(|| { + 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() )) })?; - todo!() + validate_from_to_and_status( + tx_from_rpc, + maker_address, + maker_swap_v2_contract, + maker_status, + MakerPaymentStateV2::PaymentSent as u8, + )?; + + let validation_args = { + let amount = wei_from_big_decimal(&args.amount, self.decimals)?; + MakerValidationArgs { + swap_id, + amount, + taker: self.my_addr().await, + taker_secret_hash: args.taker_secret_hash, + maker_secret_hash: args.maker_secret_hash, + 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)?; + }, + EthCoinType::Erc20 { token_addr, .. } => { + let function = MAKER_SWAP_V2.function(ERC20_MAKER_PAYMENT)?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0)?; + validate_erc20_maker_payment_data(&decoded, &validation_args, function, token_addr)?; + }, + EthCoinType::Nft { .. } => unreachable!(), + } + Ok(()) } pub(crate) async fn refund_maker_payment_v2_timelock_impl( @@ -206,3 +238,69 @@ impl EthCoin { Ok(data) } } + +/// Validation function for ETH maker payment data +fn validate_eth_maker_payment_data( + decoded: &[Token], + args: &MakerValidationArgs, + func: &Function, + tx_value: U256, +) -> Result<(), MmError> { + let checks = vec![ + (0, Token::FixedBytes(args.swap_id.clone()), "id"), + (2, Token::Address(args.taker), "taker"), + (3, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), + (4, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), + (5, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), + ]; + + for (index, expected_token, field_name) in checks { + let token = get_function_input_data(decoded, func, index).map_to_mm(ValidatePaymentError::InternalError)?; + if token != expected_token { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "ETH Maker Payment `{}` {:?} is invalid, expected {:?}", + field_name, + decoded.get(index), + expected_token + ))); + } + } + if args.amount != tx_value { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "ETH Maker Payment amount, is invalid, expected {:?}, got {:?}", + args.amount, tx_value + ))); + } + Ok(()) +} + +/// Validation function for ERC20 maker payment data +fn validate_erc20_maker_payment_data( + decoded: &[Token], + args: &MakerValidationArgs, + func: &Function, + token_addr: Address, +) -> Result<(), MmError> { + let checks = vec![ + (0, Token::FixedBytes(args.swap_id.clone()), "id"), + (1, Token::Uint(args.amount), "amount"), + (3, Token::Address(token_addr), "tokenAddress"), + (4, Token::Address(args.taker), "taker"), + (5, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), + (6, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), + (7, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), + ]; + + for (index, expected_token, field_name) in checks { + let token = get_function_input_data(decoded, func, index).map_to_mm(ValidatePaymentError::InternalError)?; + if token != expected_token { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "ERC20 Maker Payment `{}` {:?} is invalid, expected {:?}", + field_name, + decoded.get(index), + expected_token + ))); + } + } + Ok(()) +} From 619359a47df33df52251b0df6696363b477d45c0 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 1 Sep 2024 15:15:26 +0700 Subject: [PATCH 06/38] maker tpu v2: refund timelock and secret --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 171 ++++++++++++++++-- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 2 +- mm2src/coins/lp_coins.rs | 3 +- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 3 +- .../tests/docker_tests/swap_proto_v2_tests.rs | 3 +- 5 files changed, 163 insertions(+), 19 deletions(-) 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 00487848b5..0ff913d4b3 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 @@ -3,10 +3,10 @@ use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, - SpendMakerPaymentArgs, Transaction, TransactionErr, ValidateMakerPaymentArgs}; + SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, Transaction, TransactionErr, ValidateMakerPaymentArgs}; use ethabi::{Function, Token}; use ethcore_transaction::Action; -use ethereum_types::{Address, U256}; +use ethereum_types::{Address, Public, U256}; use ethkey::public_to_address; use futures::compat::Future01CompatExt; use mm2_err_handle::mm_error::MmError; @@ -33,6 +33,16 @@ struct MakerValidationArgs<'a> { payment_time_lock: u64, } +struct MakerRefundArgs { + payment_amount: U256, + taker_address: Address, + taker_secret: [u8; 32], + taker_secret_hash: [u8; 32], + maker_secret_hash: [u8; 32], + payment_time_lock: u64, + token_address: Address, +} + impl EthCoin { pub(crate) async fn send_maker_payment_v2_impl( &self, @@ -184,16 +194,111 @@ impl EthCoin { pub(crate) async fn refund_maker_payment_v2_timelock_impl( &self, - _args: RefundMakerPaymentTimelockArgs<'_>, + args: RefundMakerPaymentTimelockArgs<'_>, ) -> Result { - todo!() + let (token_address, gas_limit) = match &self.coin_type { + // TODO need new maker_v2_refund_timelock const and param for v2 calls. + EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Erc20 { + platform: _, + token_addr, + } => (*token_addr, self.gas_limit.erc20_sender_refund), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); + let (maker_secret_hash, taker_secret_hash) = match args.tx_type_with_secret_hash { + SwapTxTypeWithSecretHash::MakerPaymentV2 { + maker_secret_hash, + taker_secret_hash, + } => (maker_secret_hash, taker_secret_hash), + _ => { + return Err(TransactionErr::Plain(ERRL!( + "Unsupported swap tx type for timelock refund" + ))) + }, + }; + let args = { + let taker_address = public_to_address(&Public::from_slice(args.taker_pub)); + MakerRefundArgs { + payment_amount, + taker_address, + taker_secret: [0u8; 32], + taker_secret_hash: try_tx_s!(taker_secret_hash.try_into()), + maker_secret_hash: try_tx_s!(maker_secret_hash.try_into()), + payment_time_lock: args.time_lock, + token_address, + } + }; + let data = try_tx_s!(self.prepare_maker_refund_payment_timelock_data(args).await); + + self.sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(maker_swap_v2_contract), + data, + U256::from(gas_limit), + ) + .compat() + .await } pub(crate) async fn refund_maker_payment_v2_secret_impl( &self, - _args: RefundMakerPaymentSecretArgs<'_, Self>, + args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result { - todo!() + let (token_address, gas_limit) = match &self.coin_type { + // TODO need new maker_v2_refund_secret const and param for v2 calls. + EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Erc20 { + platform: _, + token_addr, + } => (*token_addr, self.gas_limit.erc20_sender_refund), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + let taker_secret = try_tx_s!(args.taker_secret.try_into()); + let maker_secret_hash = try_tx_s!(args.maker_secret_hash.try_into()); + let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); + let args = { + let taker_address = public_to_address(args.taker_pub); + MakerRefundArgs { + payment_amount, + taker_address, + taker_secret, + taker_secret_hash: [0u8; 32], + maker_secret_hash, + payment_time_lock: args.time_lock, + token_address, + } + }; + let data = try_tx_s!(self.prepare_maker_refund_payment_secret_data(args).await); + + self.sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(maker_swap_v2_contract), + data, + U256::from(gas_limit), + ) + .compat() + .await } pub(crate) async fn spend_maker_payment_v2_impl( @@ -237,6 +342,42 @@ impl EthCoin { ])?; Ok(data) } + + /// Prepares data for EtomicSwapMakerV2 contract [refundMakerPaymentTimelock](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L144) method + async fn prepare_maker_refund_payment_timelock_data( + &self, + args: MakerRefundArgs, + ) -> Result, PrepareTxDataError> { + let function = MAKER_SWAP_V2.function("refundMakerPaymentTimelock")?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); + let data = function.encode_input(&[ + Token::FixedBytes(id), + Token::Uint(args.payment_amount), + Token::Address(args.taker_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Address(args.token_address), + ])?; + Ok(data) + } + + /// Prepares data for EtomicSwapMakerV2 contract [refundMakerPaymentSecret](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L190) method + async fn prepare_maker_refund_payment_secret_data( + &self, + args: MakerRefundArgs, + ) -> Result, PrepareTxDataError> { + let function = MAKER_SWAP_V2.function("refundMakerPaymentSecret")?; + let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); + let data = function.encode_input(&[ + Token::FixedBytes(id), + Token::Uint(args.payment_amount), + Token::Address(args.taker_address), + Token::FixedBytes(args.taker_secret.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Address(args.token_address), + ])?; + Ok(data) + } } /// Validation function for ETH maker payment data @@ -248,10 +389,10 @@ fn validate_eth_maker_payment_data( ) -> Result<(), MmError> { let checks = vec![ (0, Token::FixedBytes(args.swap_id.clone()), "id"), - (2, Token::Address(args.taker), "taker"), - (3, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), - (4, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), - (5, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), + (1, Token::Address(args.taker), "taker"), + (2, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), + (3, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), + (4, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), ]; for (index, expected_token, field_name) in checks { @@ -284,11 +425,11 @@ fn validate_erc20_maker_payment_data( let checks = vec![ (0, Token::FixedBytes(args.swap_id.clone()), "id"), (1, Token::Uint(args.amount), "amount"), - (3, Token::Address(token_addr), "tokenAddress"), - (4, Token::Address(args.taker), "taker"), - (5, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), - (6, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), - (7, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), + (2, Token::Address(token_addr), "tokenAddress"), + (3, Token::Address(args.taker), "taker"), + (4, Token::FixedBytes(args.taker_secret_hash.to_vec()), "takerSecretHash"), + (5, Token::FixedBytes(args.maker_secret_hash.to_vec()), "makerSecretHash"), + (6, Token::Uint(U256::from(args.payment_time_lock)), "paymentLockTime"), ]; for (index, expected_token, field_name) in checks { 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 cccf6b96d1..a80e4c2083 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 @@ -255,7 +255,7 @@ impl EthCoin { args: RefundTakerPaymentArgs<'_>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new consts and params for v2 calls + // TODO need new taker_v2_refund_timelock const and param for v2 calls EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), EthCoinType::Erc20 { platform: _, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 73fd6db91e..e12cba59e6 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -996,9 +996,9 @@ pub struct RefundMakerPaymentTimelockArgs<'a> { pub time_lock: u64, pub taker_pub: &'a [u8], pub tx_type_with_secret_hash: SwapTxTypeWithSecretHash<'a>, - pub swap_contract_address: &'a Option, pub swap_unique_data: &'a [u8], pub watcher_reward: bool, + pub amount: BigDecimal, } #[derive(Debug)] @@ -1724,6 +1724,7 @@ pub struct RefundMakerPaymentSecretArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> pub taker_pub: &'a Coin::Pubkey, /// Unique data of specific swap pub swap_unique_data: &'a [u8], + pub amount: BigDecimal, } /// Common refund NFT Maker Payment structure for [MakerNftSwapOpsV2::refund_nft_maker_payment_v2_timelock] and diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 6029bd61b2..f5a6d11fa5 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -1459,6 +1459,7 @@ impl Date: Sun, 1 Sep 2024 17:51:00 +0700 Subject: [PATCH 07/38] maker tpu v2: wait_for_maker_payment_spend TODO --- mm2src/coins/eth.rs | 11 ++++++++- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 13 ++++++++-- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 6 ++--- mm2src/coins/lp_coins.rs | 24 ++++++++++++------- mm2src/coins/test_coin.rs | 4 ++-- mm2src/coins/utxo/utxo_standard.rs | 13 ++++++++-- 6 files changed, 52 insertions(+), 19 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 98cf5c7829..1bef01d3fe 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -7166,7 +7166,7 @@ impl TakerCoinSwapOpsV2 for EthCoin { taker_payment: &Self::Tx, _from_block: u64, wait_until: u64, - ) -> MmResult { + ) -> MmResult { self.wait_for_taker_payment_spend_impl(taker_payment, wait_until).await } } @@ -7262,4 +7262,13 @@ impl MakerCoinSwapOpsV2 for EthCoin { async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result { self.spend_maker_payment_v2_impl(args).await } + + async fn wait_for_maker_payment_spend( + &self, + maker_payment: &Self::Tx, + _from_block: u64, + wait_until: u64, + ) -> MmResult { + self.wait_for_maker_payment_spend_impl(maker_payment, wait_until).await + } } 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 0ff913d4b3..465fc54f58 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 @@ -3,14 +3,15 @@ use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, - SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, Transaction, TransactionErr, ValidateMakerPaymentArgs}; + SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, Transaction, TransactionErr, ValidateMakerPaymentArgs, + WaitForPaymentSpendError}; use ethabi::{Function, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, Public, U256}; use ethkey::public_to_address; use futures::compat::Future01CompatExt; use mm2_err_handle::mm_error::MmError; -use mm2_err_handle::prelude::MapToMmResult; +use mm2_err_handle::prelude::{MapToMmResult, MmResult}; use std::convert::TryInto; use web3::types::TransactionId; @@ -308,6 +309,14 @@ impl EthCoin { todo!() } + pub(crate) async fn wait_for_maker_payment_spend_impl( + &self, + _maker_payment: &SignedEthTx, + _wait_until: u64, + ) -> MmResult { + todo!() + } + /// Prepares data for EtomicSwapMakerV2 contract [ethMakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L30) method async fn prepare_maker_eth_payment_data(&self, args: &MakerPaymentArgs) -> Result, PrepareTxDataError> { let function = MAKER_SWAP_V2.function(ETH_MAKER_PAYMENT)?; 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 a80e4c2083..5aff1d2079 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 @@ -5,7 +5,7 @@ use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_dec SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, Transaction, TransactionErr, ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; use crate::{FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, SearchForFundingSpendErr, - WaitForTakerPaymentSpendError}; + WaitForPaymentSpendError}; use common::executor::Timer; use common::now_sec; use ethabi::{Function, Token}; @@ -458,7 +458,7 @@ impl EthCoin { &self, taker_payment: &SignedEthTx, wait_until: u64, - ) -> MmResult { + ) -> MmResult { let (decoded, taker_swap_v2_contract) = self .get_decoded_and_swap_contract(taker_payment, "spendTakerPayment") .await?; @@ -477,7 +477,7 @@ impl EthCoin { } let now = now_sec(); if now > wait_until { - return MmError::err(WaitForTakerPaymentSpendError::Timeout { wait_until, now }); + return MmError::err(WaitForPaymentSpendError::Timeout { wait_until, now }); } Timer::sleep(10.).await; } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index e12cba59e6..6ad882366d 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1805,6 +1805,14 @@ pub trait MakerCoinSwapOpsV2: ParseCoinAssocTypes + CommonSwapOpsV2 + Send + Syn /// Spend maker payment transaction async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result; + + /// Wait until maker payment spend is found on-chain + async fn wait_for_maker_payment_spend( + &self, + maker_payment: &Self::Tx, + from_block: u64, + wait_until: u64, + ) -> MmResult; } #[async_trait] @@ -1841,7 +1849,7 @@ pub trait MakerNftSwapOpsV2: ParseCoinAssocTypes + ParseNftAssocTypes + Send + S /// Enum representing errors that can occur while waiting for taker payment spend. #[derive(Display, Debug, EnumFromStringify)] -pub enum WaitForTakerPaymentSpendError { +pub enum WaitForPaymentSpendError { /// Timeout error variant, indicating that the wait for taker payment spend has timed out. #[display( fmt = "Timed out waiting for taker payment spend, wait_until {}, now {}", @@ -1864,20 +1872,18 @@ pub enum WaitForTakerPaymentSpendError { Transport(String), } -impl From for WaitForTakerPaymentSpendError { +impl From for WaitForPaymentSpendError { fn from(err: WaitForOutputSpendErr) -> Self { match err { - WaitForOutputSpendErr::Timeout { wait_until, now } => { - WaitForTakerPaymentSpendError::Timeout { wait_until, now } - }, + WaitForOutputSpendErr::Timeout { wait_until, now } => WaitForPaymentSpendError::Timeout { wait_until, now }, WaitForOutputSpendErr::NoOutputWithIndex(index) => { - WaitForTakerPaymentSpendError::InvalidInputTx(format!("Tx doesn't have output with index {}", index)) + WaitForPaymentSpendError::InvalidInputTx(format!("Tx doesn't have output with index {}", index)) }, } } } -impl From for WaitForTakerPaymentSpendError { +impl From for WaitForPaymentSpendError { fn from(e: PaymentStatusErr) -> Self { match e { PaymentStatusErr::ABIError(e) => Self::ABIError(e), @@ -1888,7 +1894,7 @@ impl From for WaitForTakerPaymentSpendError { } } -impl From for WaitForTakerPaymentSpendError { +impl From for WaitForPaymentSpendError { fn from(e: PrepareTxDataError) -> Self { match e { PrepareTxDataError::ABIError(e) => Self::ABIError(e), @@ -2029,7 +2035,7 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + CommonSwapOpsV2 + Send + Syn taker_payment: &Self::Tx, from_block: u64, wait_until: u64, - ) -> MmResult; + ) -> MmResult; } #[async_trait] diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 10b057ee77..4f02012202 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -2,7 +2,7 @@ use super::{CoinBalance, CommonSwapOpsV2, FundingTxSpend, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, RawTransactionRequest, RefundTakerPaymentArgs, SearchForFundingSpendErr, SwapOps, TradeFee, - TransactionEnum, TransactionFut, WaitForTakerPaymentSpendError}; + TransactionEnum, TransactionFut, WaitForPaymentSpendError}; use crate::coin_errors::ValidatePaymentResult; use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinFutSpawner, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, GenPreimageResult, GenTakerFundingSpendArgs, @@ -558,7 +558,7 @@ impl TakerCoinSwapOpsV2 for TestCoin { taker_payment: &Self::Tx, from_block: u64, wait_until: u64, - ) -> MmResult { + ) -> MmResult { unimplemented!() } } diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index d55ce40420..9a4f69ef4b 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -37,7 +37,7 @@ use crate::{CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinBalance, CoinWithDeriva ValidatePaymentError, ValidatePaymentFut, ValidatePaymentInput, ValidateSwapV2TxResult, ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageResult, ValidateTakerPaymentSpendPreimageResult, ValidateWatcherSpendInput, VerificationResult, - WaitForHTLCTxSpendArgs, WaitForTakerPaymentSpendError, WatcherOps, WatcherReward, WatcherRewardError, + WaitForHTLCTxSpendArgs, WaitForPaymentSpendError, WatcherOps, WatcherReward, WatcherRewardError, WatcherSearchForSwapTxSpendInput, WatcherValidatePaymentInput, WatcherValidateTakerFeeInput, WithdrawFut}; use common::executor::{AbortableSystem, AbortedError}; use futures::{FutureExt, TryFutureExt}; @@ -663,6 +663,15 @@ impl MakerCoinSwapOpsV2 for UtxoStandardCoin { async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result { utxo_common::spend_maker_payment_v2(self, args).await } + + async fn wait_for_maker_payment_spend( + &self, + _maker_payment: &Self::Tx, + _from_block: u64, + _wait_until: u64, + ) -> MmResult { + todo!() + } } #[async_trait] @@ -848,7 +857,7 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { taker_payment: &Self::Tx, from_block: u64, wait_until: u64, - ) -> MmResult { + ) -> MmResult { let res = utxo_common::wait_for_output_spend_impl( self.as_ref(), taker_payment, From e16bf49c2bc46e178e1b1c102d1e17a1694db720 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 2 Sep 2024 13:10:23 +0700 Subject: [PATCH 08/38] maker tpu v2: spend_maker_payment_v2_impl --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 64 +++++++++++++++++-- mm2src/coins/lp_coins.rs | 1 + mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 1 + 3 files changed, 59 insertions(+), 7 deletions(-) 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 465fc54f58..00c99615bc 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 @@ -240,7 +240,7 @@ impl EthCoin { token_address, } }; - let data = try_tx_s!(self.prepare_maker_refund_payment_timelock_data(args).await); + let data = try_tx_s!(self.prepare_refund_maker_payment_timelock_data(args).await); self.sign_and_send_transaction( U256::from(ZERO_VALUE), @@ -257,7 +257,7 @@ impl EthCoin { args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new maker_v2_refund_secret const and param for v2 calls. + // TODO need new maker_refund_secret_v2 const and param for v2 calls. EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), EthCoinType::Erc20 { platform: _, @@ -290,7 +290,7 @@ impl EthCoin { token_address, } }; - let data = try_tx_s!(self.prepare_maker_refund_payment_secret_data(args).await); + let data = try_tx_s!(self.prepare_refund_maker_payment_secret_data(args).await); self.sign_and_send_transaction( U256::from(ZERO_VALUE), @@ -304,9 +304,37 @@ impl EthCoin { pub(crate) async fn spend_maker_payment_v2_impl( &self, - _args: SpendMakerPaymentArgs<'_, Self>, + args: SpendMakerPaymentArgs<'_, Self>, ) -> Result { - todo!() + // TODO need new maker_spend_v2 const and param + let (token_address, gas_limit) = match &self.coin_type { + EthCoinType::Eth => (Address::default(), U256::from(self.gas_limit.eth_receiver_spend)), + EthCoinType::Erc20 { + platform: _, + token_addr, + } => (*token_addr, U256::from(self.gas_limit.erc20_receiver_spend)), + EthCoinType::Nft { .. } => { + return Err(TransactionErr::ProtocolNotSupported(ERRL!( + "NFT protocol is not supported for ETH and ERC20 Swaps" + ))) + }, + }; + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + + let data = try_tx_s!(self.prepare_spend_maker_payment_data(args, token_address).await); + + self.sign_and_send_transaction( + U256::from(ZERO_VALUE), + Action::Call(maker_swap_v2_contract), + data, + gas_limit, + ) + .compat() + .await } pub(crate) async fn wait_for_maker_payment_spend_impl( @@ -353,7 +381,7 @@ impl EthCoin { } /// Prepares data for EtomicSwapMakerV2 contract [refundMakerPaymentTimelock](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L144) method - async fn prepare_maker_refund_payment_timelock_data( + async fn prepare_refund_maker_payment_timelock_data( &self, args: MakerRefundArgs, ) -> Result, PrepareTxDataError> { @@ -371,7 +399,7 @@ impl EthCoin { } /// Prepares data for EtomicSwapMakerV2 contract [refundMakerPaymentSecret](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L190) method - async fn prepare_maker_refund_payment_secret_data( + async fn prepare_refund_maker_payment_secret_data( &self, args: MakerRefundArgs, ) -> Result, PrepareTxDataError> { @@ -387,6 +415,28 @@ impl EthCoin { ])?; Ok(data) } + + /// Prepares data for EtomicSwapMakerV2 contract [spendMakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L104) method + async fn prepare_spend_maker_payment_data( + &self, + args: SpendMakerPaymentArgs<'_, Self>, + token_address: Address, + ) -> Result, PrepareTxDataError> { + let function = MAKER_SWAP_V2.function("spendMakerPayment")?; + let id = self.etomic_swap_id_v2(args.time_lock, args.maker_secret_hash); + let maker_address = public_to_address(args.maker_pub); + let payment_amount = wei_from_big_decimal(&args.amount, self.decimals) + .map_err(|e| PrepareTxDataError::Internal(e.to_string()))?; + let data = function.encode_input(&[ + Token::FixedBytes(id), + Token::Uint(payment_amount), + Token::Address(maker_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + Token::Address(token_address), + ])?; + Ok(data) + } } /// Validation function for ETH maker payment data diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 6ad882366d..37627ed08f 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1761,6 +1761,7 @@ pub struct SpendMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub maker_pub: &'a Coin::Pubkey, /// Unique data of specific swap pub swap_unique_data: &'a [u8], + pub amount: BigDecimal, } pub struct SpendNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftAssocTypes + ?Sized> { diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index edeafa57b6..d7c847c4ac 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -2095,6 +2095,7 @@ impl tx, From b35e68fbf73cce3db1e8c68e2d815e4e00d92caa Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 2 Sep 2024 15:43:53 +0700 Subject: [PATCH 09/38] eth maker tpu v2: wait_for_maker_payment_spend_impl --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) 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 00c99615bc..501ab7e4fe 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 @@ -5,6 +5,8 @@ use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_dec use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, Transaction, TransactionErr, ValidateMakerPaymentArgs, WaitForPaymentSpendError}; +use common::executor::Timer; +use common::now_sec; use ethabi::{Function, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, Public, U256}; @@ -198,7 +200,7 @@ impl EthCoin { args: RefundMakerPaymentTimelockArgs<'_>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new maker_v2_refund_timelock const and param for v2 calls. + // TODO need new refund_maker_timelock_v2 const and param for v2 calls. EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), EthCoinType::Erc20 { platform: _, @@ -257,7 +259,7 @@ impl EthCoin { args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new maker_refund_secret_v2 const and param for v2 calls. + // TODO need new refund_maker_secret_v2 const and param for v2 calls. EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), EthCoinType::Erc20 { platform: _, @@ -306,7 +308,7 @@ impl EthCoin { &self, args: SpendMakerPaymentArgs<'_, Self>, ) -> Result { - // TODO need new maker_spend_v2 const and param + // TODO need new spend_maker_v2 const and param let (token_address, gas_limit) = match &self.coin_type { EthCoinType::Eth => (Address::default(), U256::from(self.gas_limit.eth_receiver_spend)), EthCoinType::Erc20 { @@ -339,10 +341,46 @@ impl EthCoin { pub(crate) async fn wait_for_maker_payment_spend_impl( &self, - _maker_payment: &SignedEthTx, - _wait_until: u64, + maker_payment: &SignedEthTx, + wait_until: u64, ) -> MmResult { - todo!() + let decoded = { + let func = match self.coin_type { + EthCoinType::Eth | EthCoinType::Erc20 { .. } => MAKER_SWAP_V2.function("spendMakerPayment")?, + EthCoinType::Nft { .. } => { + return MmError::err(WaitForPaymentSpendError::Internal( + "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), + )); + }, + }; + decode_contract_call(func, maker_payment.unsigned().data())? + }; + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| { + WaitForPaymentSpendError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) + })?; + loop { + let maker_status = self + .payment_status_v2( + maker_swap_v2_contract, + decoded[0].clone(), // id from spendMakerPayment + &MAKER_SWAP_V2, + EthPaymentType::MakerPayments, + 2, + ) + .await?; + if maker_status == U256::from(MakerPaymentStateV2::TakerSpent as u8) { + return Ok(maker_payment.clone()); + } + let now = now_sec(); + if now > wait_until { + return MmError::err(WaitForPaymentSpendError::Timeout { wait_until, now }); + } + Timer::sleep(10.).await; + } } /// Prepares data for EtomicSwapMakerV2 contract [ethMakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L30) method From f73b5dee0fefffbe61720c2cf3993ff4bacc174e Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 3 Sep 2024 08:59:50 +0700 Subject: [PATCH 10/38] eth maker v2 docker tests --- .../tests/docker_tests/eth_docker_tests.rs | 311 +++++++++++++++++- 1 file changed, 307 insertions(+), 4 deletions(-) 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 3a898b0f2f..e6b3f53fad 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -13,12 +13,14 @@ use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_reque use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CoinsContext, CommonSwapOpsV2, ConfirmPaymentInput, DerivationMethod, DexFee, Eip1559Ops, FoundSwapTxSpend, FundingTxSpend, GenTakerFundingSpendArgs, - GenTakerPaymentSpendArgs, MakerNftSwapOpsV2, MarketCoinOps, MmCoinEnum, MmCoinStruct, NftSwapInfo, - ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, RefundFundingSecretArgs, - RefundNftMakerPaymentArgs, RefundPaymentArgs, RefundTakerPaymentArgs, SearchForSwapTxSpendInput, + GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MakerNftSwapOpsV2, MarketCoinOps, MmCoinEnum, MmCoinStruct, + NftSwapInfo, ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, RefundFundingSecretArgs, + RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundNftMakerPaymentArgs, + RefundPaymentArgs, RefundTakerPaymentArgs, SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendNftMakerPaymentArgs, SendPaymentArgs, SendTakerFundingArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, - Transaction, TxPreimageWithSig, ValidateNftMakerPaymentArgs, ValidateTakerFundingArgs}; + Transaction, TxPreimageWithSig, ValidateMakerPaymentArgs, ValidateNftMakerPaymentArgs, + ValidateTakerFundingArgs}; use common::{block_on, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; @@ -2094,3 +2096,304 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { ); wait_for_confirmations(&taker_coin, &funding_tx_refund, 150); } + +#[ignore] +#[test] +fn send_maker_payment_and_refund_timelock_eth() { + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let payment_time_lock = now_sec() - 1000; + + let maker_address = block_on(maker_coin.my_addr()); + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let payment_args = SendMakerPaymentArgs { + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + taker_pub, + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx = block_on(maker_coin.send_maker_payment_v2(payment_args)).unwrap(); + log!("Maker sent ETH payment, tx hash: {:02x}", payment_tx.tx_hash()); + wait_for_confirmations(&maker_coin, &payment_tx, 100); + + let tx_type_with_secret_hash = SwapTxTypeWithSecretHash::MakerPaymentV2 { + maker_secret_hash: &maker_secret_hash, + taker_secret_hash: &taker_secret_hash, + }; + let refund_args = RefundMakerPaymentTimelockArgs { + payment_tx: &payment_tx.to_bytes(), + time_lock: payment_time_lock, + taker_pub: &taker_pub.to_bytes(), + tx_type_with_secret_hash, + swap_unique_data: &[], + watcher_reward: false, + amount: trading_amount, + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx_refund = block_on(maker_coin.refund_maker_payment_v2_timelock(refund_args)).unwrap(); + log!( + "Maker refunded ETH payment after timelock, tx hash: {:02x}", + payment_tx_refund.tx_hash() + ); + wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); +} + +#[ignore] +#[test] +fn send_maker_payment_and_refund_timelock_erc20() { + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let payment_time_lock = now_sec() - 1000; + + let maker_address = block_on(maker_coin.my_addr()); + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let payment_args = SendMakerPaymentArgs { + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + taker_pub, + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx = block_on(maker_coin.send_maker_payment_v2(payment_args)).unwrap(); + log!("Maker sent ERC20 payment, tx hash: {:02x}", payment_tx.tx_hash()); + wait_for_confirmations(&maker_coin, &payment_tx, 100); + + let tx_type_with_secret_hash = SwapTxTypeWithSecretHash::MakerPaymentV2 { + maker_secret_hash: &maker_secret_hash, + taker_secret_hash: &taker_secret_hash, + }; + let refund_args = RefundMakerPaymentTimelockArgs { + payment_tx: &payment_tx.to_bytes(), + time_lock: payment_time_lock, + taker_pub: &taker_pub.to_bytes(), + tx_type_with_secret_hash, + swap_unique_data: &[], + watcher_reward: false, + amount: trading_amount, + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx_refund = block_on(maker_coin.refund_maker_payment_v2_timelock(refund_args)).unwrap(); + log!( + "Maker refunded ERC20 payment after timelock, tx hash: {:02x}", + payment_tx_refund.tx_hash() + ); + wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); +} + +#[ignore] +#[test] +fn send_maker_payment_and_refund_secret_eth() { + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let payment_time_lock = now_sec() + 1000; + + let maker_address = block_on(maker_coin.my_addr()); + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let payment_args = SendMakerPaymentArgs { + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + taker_pub, + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx = block_on(maker_coin.send_maker_payment_v2(payment_args)).unwrap(); + log!("Maker sent ETH payment, tx hash: {:02x}", payment_tx.tx_hash()); + wait_for_confirmations(&maker_coin, &payment_tx, 100); + + let refund_args = RefundMakerPaymentSecretArgs { + maker_payment_tx: &payment_tx, + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + taker_secret: &taker_secret, + taker_pub, + swap_unique_data: &[], + amount: trading_amount, + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx_refund = block_on(maker_coin.refund_maker_payment_v2_secret(refund_args)).unwrap(); + log!( + "Maker refunded ETH payment using taker secret, tx hash: {:02x}", + payment_tx_refund.tx_hash() + ); + wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); +} + +#[ignore] +#[test] +fn send_maker_payment_and_refund_secret_erc20() { + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let payment_time_lock = now_sec() + 1000; + + let maker_address = block_on(maker_coin.my_addr()); + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let payment_args = SendMakerPaymentArgs { + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + taker_pub, + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx = block_on(maker_coin.send_maker_payment_v2(payment_args)).unwrap(); + log!("Maker sent ERC20 payment, tx hash: {:02x}", payment_tx.tx_hash()); + wait_for_confirmations(&maker_coin, &payment_tx, 100); + + let refund_args = RefundMakerPaymentSecretArgs { + maker_payment_tx: &payment_tx, + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + taker_secret: &taker_secret, + taker_pub, + swap_unique_data: &[], + amount: trading_amount, + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx_refund = block_on(maker_coin.refund_maker_payment_v2_secret(refund_args)).unwrap(); + log!( + "Maker refunded ERC20 payment using taker secret, tx hash: {:02x}", + payment_tx_refund.tx_hash() + ); + wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); +} + +#[ignore] +#[test] +fn send_and_spend_maker_payment_eth() { + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let payment_time_lock = now_sec() + 1000; + + let maker_address = block_on(maker_coin.my_addr()); + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let payment_args = SendMakerPaymentArgs { + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + taker_pub, + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx = block_on(maker_coin.send_maker_payment_v2(payment_args)).unwrap(); + log!("Maker sent ETH payment, tx hash: {:02x}", payment_tx.tx_hash()); + wait_for_confirmations(&maker_coin, &payment_tx, 100); + + let validation_args = ValidateMakerPaymentArgs { + maker_payment_tx: &payment_tx, + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + maker_pub, + swap_unique_data: &[], + }; + block_on(taker_coin.validate_maker_payment_v2(validation_args)).unwrap(); + log!("Taker validated maker ETH payment"); + + // TODO spend_maker_payment_v2 + + // TODO wait_for_maker_payment_spend +} + +#[ignore] +#[test] +fn send_and_spend_maker_payment_erc20() { + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); + let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); + + let taker_secret = vec![0; 32]; + let taker_secret_hash = sha256(&taker_secret).to_vec(); + let maker_secret = vec![1; 32]; + let maker_secret_hash = sha256(&maker_secret).to_vec(); + let payment_time_lock = now_sec() + 1000; + + let maker_address = block_on(maker_coin.my_addr()); + let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); + let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); + + let trading_amount = BigDecimal::from_str("0.0001").unwrap(); + + let payment_args = SendMakerPaymentArgs { + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + taker_pub, + swap_unique_data: &[], + }; + wait_pending_transactions(Address::from_slice(maker_address.as_bytes())); + let payment_tx = block_on(maker_coin.send_maker_payment_v2(payment_args)).unwrap(); + log!("Maker sent ERC20 payment, tx hash: {:02x}", payment_tx.tx_hash()); + wait_for_confirmations(&maker_coin, &payment_tx, 100); + + let validation_args = ValidateMakerPaymentArgs { + maker_payment_tx: &payment_tx, + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + amount: trading_amount.clone(), + maker_pub, + swap_unique_data: &[], + }; + block_on(taker_coin.validate_maker_payment_v2(validation_args)).unwrap(); + log!("Taker validated maker ERC20 payment"); + + // TODO spend_maker_payment_v2 + + // TODO wait_for_maker_payment_spend +} From e53c028f47d88e599db82ef15cc578900b5c2d43 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 5 Sep 2024 12:36:01 +0700 Subject: [PATCH 11/38] remove clone for now --- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 e6b3f53fad..05b44a581e 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -2337,7 +2337,7 @@ fn send_and_spend_maker_payment_eth() { time_lock: payment_time_lock, taker_secret_hash: &taker_secret_hash, maker_secret_hash: &maker_secret_hash, - amount: trading_amount.clone(), + amount: trading_amount, maker_pub, swap_unique_data: &[], }; @@ -2386,7 +2386,7 @@ fn send_and_spend_maker_payment_erc20() { time_lock: payment_time_lock, taker_secret_hash: &taker_secret_hash, maker_secret_hash: &maker_secret_hash, - amount: trading_amount.clone(), + amount: trading_amount, maker_pub, swap_unique_data: &[], }; From 7498eec9ff9b22bf8bf186424740838ddd410c60 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 8 Sep 2024 13:35:17 +0700 Subject: [PATCH 12/38] maker swap v2 docker tests (on sepolia) --- .../tests/docker_tests/docker_tests_common.rs | 4 +- .../tests/docker_tests/eth_docker_tests.rs | 59 ++++++++++++++----- 2 files changed, 45 insertions(+), 18 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 fe5d7f96d4..00a713bb62 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -1586,8 +1586,8 @@ pub fn init_geth_node() { SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 = EthAddress::from_str("0x9eb88cd58605d8fb9b14652d6152727f7e95fb4d").unwrap(); SEPOLIA_ERC20_CONTRACT = EthAddress::from_str("0xF7b5F8E8555EF7A743f24D3E974E23A3C6cB6638").unwrap(); SEPOLIA_TAKER_SWAP_V2 = EthAddress::from_str("0x7Cc9F2c1c3B797D09B9d1CCd7FDcD2539a4b3874").unwrap(); - // TODO update this - SEPOLIA_MAKER_SWAP_V2 = EthAddress::from_str("0x7Cc9F2c1c3B797D09B9d1CCd7FDcD2539a4b3874").unwrap(); + // deploy tx https://sepolia.etherscan.io/tx/0x6f743d79ecb806f5899a6a801083e33eba9e6f10726af0873af9f39883db7f11 + SEPOLIA_MAKER_SWAP_V2 = EthAddress::from_str("0xf9000589c66Df3573645B59c10aa87594Edc318F").unwrap(); let alice_passphrase = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let alice_keypair = key_pair_from_seed(&alice_passphrase).unwrap(); 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 05b44a581e..a4cd19a142 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -17,10 +17,10 @@ use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CoinsContext, C NftSwapInfo, ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, RefundFundingSecretArgs, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundNftMakerPaymentArgs, RefundPaymentArgs, RefundTakerPaymentArgs, SearchForSwapTxSpendInput, SendMakerPaymentArgs, - SendNftMakerPaymentArgs, SendPaymentArgs, SendTakerFundingArgs, SpendNftMakerPaymentArgs, - SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, - Transaction, TxPreimageWithSig, ValidateMakerPaymentArgs, ValidateNftMakerPaymentArgs, - ValidateTakerFundingArgs}; + SendNftMakerPaymentArgs, SendPaymentArgs, SendTakerFundingArgs, SpendMakerPaymentArgs, + SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, + TakerCoinSwapOpsV2, ToBytes, Transaction, TxPreimageWithSig, ValidateMakerPaymentArgs, + ValidateNftMakerPaymentArgs, ValidateTakerFundingArgs}; use common::{block_on, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; @@ -2097,9 +2097,9 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 150); } -#[ignore] #[test] fn send_maker_payment_and_refund_timelock_eth() { + thread::sleep(Duration::from_secs(150)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2149,9 +2149,9 @@ fn send_maker_payment_and_refund_timelock_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_maker_payment_and_refund_timelock_erc20() { + thread::sleep(Duration::from_secs(120)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2202,9 +2202,9 @@ fn send_maker_payment_and_refund_timelock_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_maker_payment_and_refund_secret_eth() { + thread::sleep(Duration::from_secs(90)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2251,9 +2251,9 @@ fn send_maker_payment_and_refund_secret_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_maker_payment_and_refund_secret_erc20() { + thread::sleep(Duration::from_secs(60)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2301,7 +2301,6 @@ fn send_maker_payment_and_refund_secret_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_and_spend_maker_payment_eth() { let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2314,6 +2313,7 @@ fn send_and_spend_maker_payment_eth() { let payment_time_lock = now_sec() + 1000; let maker_address = block_on(maker_coin.my_addr()); + let taker_address = block_on(taker_coin.my_addr()); let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); @@ -2337,21 +2337,34 @@ fn send_and_spend_maker_payment_eth() { time_lock: payment_time_lock, taker_secret_hash: &taker_secret_hash, maker_secret_hash: &maker_secret_hash, - amount: trading_amount, + amount: trading_amount.clone(), maker_pub, swap_unique_data: &[], }; block_on(taker_coin.validate_maker_payment_v2(validation_args)).unwrap(); log!("Taker validated maker ETH payment"); - // TODO spend_maker_payment_v2 + let spend_args = SpendMakerPaymentArgs { + maker_payment_tx: &payment_tx, + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_secret: &maker_secret, + maker_pub, + swap_unique_data: &[], + amount: trading_amount, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let spend_tx = block_on(taker_coin.spend_maker_payment_v2(spend_args)).unwrap(); + log!("Taker spent maker ETH payment, tx hash: {:02x}", spend_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &spend_tx, 100); - // TODO wait_for_maker_payment_spend + block_on(maker_coin.wait_for_maker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } -#[ignore] #[test] fn send_and_spend_maker_payment_erc20() { + thread::sleep(Duration::from_secs(30)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2363,6 +2376,7 @@ fn send_and_spend_maker_payment_erc20() { let payment_time_lock = now_sec() + 1000; let maker_address = block_on(maker_coin.my_addr()); + let taker_address = block_on(taker_coin.my_addr()); let maker_pub = &maker_coin.derive_htlc_pubkey_v2(&[]); let taker_pub = &taker_coin.derive_htlc_pubkey_v2(&[]); @@ -2386,14 +2400,27 @@ fn send_and_spend_maker_payment_erc20() { time_lock: payment_time_lock, taker_secret_hash: &taker_secret_hash, maker_secret_hash: &maker_secret_hash, - amount: trading_amount, + amount: trading_amount.clone(), maker_pub, swap_unique_data: &[], }; block_on(taker_coin.validate_maker_payment_v2(validation_args)).unwrap(); log!("Taker validated maker ERC20 payment"); - // TODO spend_maker_payment_v2 + let spend_args = SpendMakerPaymentArgs { + maker_payment_tx: &payment_tx, + time_lock: payment_time_lock, + taker_secret_hash: &taker_secret_hash, + maker_secret_hash: &maker_secret_hash, + maker_secret: &maker_secret, + maker_pub, + swap_unique_data: &[], + amount: trading_amount, + }; + wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); + let spend_tx = block_on(taker_coin.spend_maker_payment_v2(spend_args)).unwrap(); + log!("Taker spent maker ERC20 payment, tx hash: {:02x}", spend_tx.tx_hash()); + wait_for_confirmations(&taker_coin, &spend_tx, 100); - // TODO wait_for_maker_payment_spend + block_on(maker_coin.wait_for_maker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } From b1626f7a7c1609a2166777ed692e6914e7c30318 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 9 Sep 2024 20:32:18 +0700 Subject: [PATCH 13/38] set taker and maker gas limits V2 --- mm2src/coins/eth.rs | 122 +++++++++++++++++- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 21 ++- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 24 ++-- mm2src/coins/eth/for_tests.rs | 4 +- mm2src/coins/eth/v2_activation.rs | 15 ++- 5 files changed, 148 insertions(+), 38 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 1bef01d3fe..fa157ae28c 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -245,12 +245,40 @@ pub mod gas_limit { pub const ERC20_RECEIVER_SPEND: u64 = 150_000; /// Gas limit for swap refund tx with coins pub const ETH_SENDER_REFUND: u64 = 100_000; - /// Gas limit for swap refund tx with with ERC20 tokens + /// Gas limit for swap refund tx with ERC20 tokens pub const ERC20_SENDER_REFUND: u64 = 150_000; /// Gas limit for other operations pub const ETH_MAX_TRADE_GAS: u64 = 150_000; } +/// Gas limits for EthGasLimitV2 +pub mod gas_limit_v2 { + /// Gas limits for maker operations in EthGasLimitV2 + pub mod maker { + pub const ETH_SEND_PAYMENT: u64 = 65_000; + pub const ERC20_SEND_PAYMENT: u64 = 115_000; + pub const ETH_TAKER_SPEND: u64 = 65_000; + pub const ERC20_TAKER_SPEND: u64 = 65_000; + pub const ETH_MAKER_REFUND_TIMELOCK: u64 = 65_000; + pub const ERC20_MAKER_REFUND_TIMELOCK: u64 = 65_000; + pub const ETH_MAKER_REFUND_SECRET: u64 = 65_000; + pub const ERC20_MAKER_REFUND_SECRET: u64 = 65_000; + } + + /// Gas limits for taker operations in EthGasLimitV2 + pub mod taker { + pub const ETH_SEND_PAYMENT: u64 = 65_000; + pub const ERC20_SEND_PAYMENT: u64 = 115_000; + pub const ETH_MAKER_SPEND: u64 = 65_000; + pub const ERC20_MAKER_SPEND: u64 = 115_000; + pub const ETH_TAKER_REFUND_TIMELOCK: u64 = 65_000; + pub const ERC20_TAKER_REFUND_TIMELOCK: u64 = 70_000; + pub const ETH_TAKER_REFUND_SECRET: u64 = 65_000; + pub const ERC20_TAKER_REFUND_SECRET: u64 = 70_000; + pub const APPROVE_PAYMENT: u64 = 50_000; + } +} + /// Coin conf param to override default gas limits #[derive(Deserialize)] #[serde(default)] @@ -269,7 +297,7 @@ pub struct EthGasLimit { pub erc20_receiver_spend: u64, /// Gas limit for swap refund tx with coins pub eth_sender_refund: u64, - /// Gas limit for swap refund tx with with ERC20 tokens + /// Gas limit for swap refund tx with ERC20 tokens pub erc20_sender_refund: u64, /// Gas limit for other operations pub eth_max_trade_gas: u64, @@ -291,6 +319,83 @@ impl Default for EthGasLimit { } } +#[derive(Default, Deserialize)] +#[serde(default)] +pub struct EthGasLimitV2 { + pub maker: MakerGasLimitV2, + pub taker: TakerGasLimitV2, +} + +#[derive(Deserialize)] +#[serde(default)] +pub struct MakerGasLimitV2 { + pub eth_send_payment: u64, + pub erc20_send_payment: u64, + pub eth_taker_spend: u64, + pub erc20_taker_spend: u64, + pub eth_maker_refund_timelock: u64, + pub erc20_maker_refund_timelock: u64, + pub eth_maker_refund_secret: u64, + pub erc20_maker_refund_secret: u64, +} + +#[derive(Deserialize)] +#[serde(default)] +pub struct TakerGasLimitV2 { + pub eth_send_payment: u64, + pub erc20_send_payment: u64, + pub eth_maker_spend: u64, + pub erc20_maker_spend: u64, + pub eth_taker_refund_timelock: u64, + pub erc20_taker_refund_timelock: u64, + pub eth_taker_refund_secret: u64, + pub erc20_taker_refund_secret: u64, + pub approve_payment: u64, +} + +impl Default for MakerGasLimitV2 { + fn default() -> Self { + MakerGasLimitV2 { + eth_send_payment: gas_limit_v2::maker::ETH_SEND_PAYMENT, + erc20_send_payment: gas_limit_v2::maker::ERC20_SEND_PAYMENT, + eth_taker_spend: gas_limit_v2::maker::ETH_TAKER_SPEND, + erc20_taker_spend: gas_limit_v2::maker::ERC20_TAKER_SPEND, + eth_maker_refund_timelock: gas_limit_v2::maker::ETH_MAKER_REFUND_TIMELOCK, + erc20_maker_refund_timelock: gas_limit_v2::maker::ERC20_MAKER_REFUND_TIMELOCK, + eth_maker_refund_secret: gas_limit_v2::maker::ETH_MAKER_REFUND_SECRET, + erc20_maker_refund_secret: gas_limit_v2::maker::ERC20_MAKER_REFUND_SECRET, + } + } +} + +impl Default for TakerGasLimitV2 { + fn default() -> Self { + TakerGasLimitV2 { + eth_send_payment: gas_limit_v2::taker::ETH_SEND_PAYMENT, + erc20_send_payment: gas_limit_v2::taker::ERC20_SEND_PAYMENT, + eth_maker_spend: gas_limit_v2::taker::ETH_MAKER_SPEND, + erc20_maker_spend: gas_limit_v2::taker::ERC20_MAKER_SPEND, + eth_taker_refund_timelock: gas_limit_v2::taker::ETH_TAKER_REFUND_TIMELOCK, + erc20_taker_refund_timelock: gas_limit_v2::taker::ERC20_TAKER_REFUND_TIMELOCK, + eth_taker_refund_secret: gas_limit_v2::taker::ETH_TAKER_REFUND_SECRET, + erc20_taker_refund_secret: gas_limit_v2::taker::ERC20_TAKER_REFUND_SECRET, + approve_payment: gas_limit_v2::taker::APPROVE_PAYMENT, + } + } +} + +trait ExtractGasLimit: Default + for<'de> Deserialize<'de> { + fn key() -> &'static str; +} + +impl ExtractGasLimit for EthGasLimit { + fn key() -> &'static str { "gas_limit" } +} + +impl ExtractGasLimit for EthGasLimitV2 { + fn key() -> &'static str { "gas_limit_v2" } +} + /// Max transaction type according to EIP-2718 const ETH_MAX_TX_TYPE: u64 = 0x7f; @@ -681,6 +786,7 @@ pub struct EthCoinImpl { pub(crate) platform_fee_estimator_state: Arc, /// Config provided gas limits for swap and send transactions pub(crate) gas_limit: EthGasLimit, + pub(crate) gas_limit_v2: EthGasLimitV2, /// This spawner is used to spawn coin's related futures that should be aborted on coin deactivation /// and on [`MmArc::stop`]. pub abortable_system: AbortableQueue, @@ -6386,7 +6492,8 @@ pub async fn eth_coin_from_conf_and_request( let platform_fee_estimator_state = FeeEstimatorState::init_fee_estimator(ctx, conf, &coin_type).await?; let max_eth_tx_type = get_max_eth_tx_type_conf(ctx, conf, &coin_type).await?; - let gas_limit = extract_gas_limit_from_conf(conf)?; + let gas_limit: EthGasLimit = extract_gas_limit_from_conf(conf)?; + let gas_limit_v2: EthGasLimitV2 = extract_gas_limit_from_conf(conf)?; let coin = EthCoinImpl { priv_key_policy: key_pair, @@ -6413,6 +6520,7 @@ pub async fn eth_coin_from_conf_and_request( nfts_infos: Default::default(), platform_fee_estimator_state, gas_limit, + gas_limit_v2, abortable_system, }; @@ -7038,11 +7146,12 @@ pub fn pubkey_from_extended(extended_pubkey: &Secp256k1ExtendedPublicKey) -> Pub pubkey_uncompressed } -fn extract_gas_limit_from_conf(coin_conf: &Json) -> Result { - if coin_conf["gas_limit"].is_null() { +fn extract_gas_limit_from_conf(coin_conf: &Json) -> Result { + let key = T::key(); + if coin_conf[key].is_null() { Ok(Default::default()) } else { - json::from_value(coin_conf["gas_limit"].clone()).map_err(|e| e.to_string()) + json::from_value(coin_conf[key].clone()).map_err(|e| e.to_string()) } } @@ -7229,6 +7338,7 @@ impl EthCoin { nfts_infos: Arc::clone(&self.nfts_infos), platform_fee_estimator_state: Arc::clone(&self.platform_fee_estimator_state), gas_limit: EthGasLimit::default(), + gas_limit_v2: EthGasLimitV2::default(), abortable_system: self.abortable_system.create_subsystem().unwrap(), }; EthCoin(Arc::new(coin)) 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 501ab7e4fe..fb9446b88b 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 @@ -73,8 +73,7 @@ impl EthCoin { payment_amount, Action::Call(maker_swap_v2_contract), data, - // TODO need new consts and params for v2 calls. now it uses v1 - U256::from(self.gas_limit.eth_payment), + U256::from(self.gas_limit_v2.maker.eth_send_payment), ) .compat() .await @@ -109,8 +108,7 @@ impl EthCoin { U256::from(ZERO_VALUE), Action::Call(maker_swap_v2_contract), data, - // TODO need new consts and params for v2 calls. now it uses v1 - U256::from(self.gas_limit.erc20_payment), + U256::from(self.gas_limit_v2.maker.erc20_send_payment), ) .compat() .await @@ -200,12 +198,11 @@ impl EthCoin { args: RefundMakerPaymentTimelockArgs<'_>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new refund_maker_timelock_v2 const and param for v2 calls. - EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Eth => (Address::default(), self.gas_limit_v2.maker.eth_maker_refund_timelock), EthCoinType::Erc20 { platform: _, token_addr, - } => (*token_addr, self.gas_limit.erc20_sender_refund), + } => (*token_addr, self.gas_limit_v2.maker.erc20_maker_refund_timelock), EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( "NFT protocol is not supported for ETH and ERC20 Swaps" @@ -259,12 +256,11 @@ impl EthCoin { args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new refund_maker_secret_v2 const and param for v2 calls. - EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Eth => (Address::default(), self.gas_limit_v2.maker.eth_maker_refund_secret), EthCoinType::Erc20 { platform: _, token_addr, - } => (*token_addr, self.gas_limit.erc20_sender_refund), + } => (*token_addr, self.gas_limit_v2.maker.erc20_maker_refund_secret), EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( "NFT protocol is not supported for ETH and ERC20 Swaps" @@ -308,13 +304,12 @@ impl EthCoin { &self, args: SpendMakerPaymentArgs<'_, Self>, ) -> Result { - // TODO need new spend_maker_v2 const and param let (token_address, gas_limit) = match &self.coin_type { - EthCoinType::Eth => (Address::default(), U256::from(self.gas_limit.eth_receiver_spend)), + EthCoinType::Eth => (Address::default(), U256::from(self.gas_limit_v2.maker.eth_taker_spend)), EthCoinType::Erc20 { platform: _, token_addr, - } => (*token_addr, U256::from(self.gas_limit.erc20_receiver_spend)), + } => (*token_addr, U256::from(self.gas_limit_v2.maker.erc20_taker_spend)), EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( "NFT protocol is not supported for ETH and ERC20 Swaps" 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 5aff1d2079..126f8a00d5 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 @@ -83,8 +83,7 @@ impl EthCoin { eth_total_payment, Action::Call(taker_swap_v2_contract), data, - // TODO need new consts and params for v2 calls. now it uses v1 - U256::from(self.gas_limit.eth_payment), + U256::from(self.gas_limit_v2.taker.eth_send_payment), ) .compat() .await @@ -116,8 +115,7 @@ impl EthCoin { U256::from(ZERO_VALUE), Action::Call(taker_swap_v2_contract), data, - // TODO need new consts and params for v2 calls. now it uses v1 - U256::from(self.gas_limit.erc20_payment), + U256::from(self.gas_limit_v2.taker.erc20_send_payment), ) .compat() .await @@ -209,9 +207,8 @@ impl EthCoin { &self, args: &GenTakerFundingSpendArgs<'_, Self>, ) -> Result { - // TODO need new consts and params for v2 calls, here should be common `gas_limit.taker_approve` param for Eth and Erc20 let gas_limit = match self.coin_type { - EthCoinType::Eth | EthCoinType::Erc20 { .. } => U256::from(self.gas_limit.eth_payment), + EthCoinType::Eth | EthCoinType::Erc20 { .. } => U256::from(self.gas_limit_v2.taker.approve_payment), EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( "NFT protocol is not supported for ETH and ERC20 Swaps" @@ -255,12 +252,11 @@ impl EthCoin { args: RefundTakerPaymentArgs<'_>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new taker_v2_refund_timelock const and param for v2 calls - EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Eth => (Address::default(), self.gas_limit_v2.taker.eth_taker_refund_timelock), EthCoinType::Erc20 { platform: _, token_addr, - } => (*token_addr, self.gas_limit.erc20_sender_refund), + } => (*token_addr, self.gas_limit_v2.taker.erc20_taker_refund_timelock), EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( "NFT protocol is not supported for ETH and ERC20 Swaps" @@ -321,12 +317,11 @@ impl EthCoin { args: RefundFundingSecretArgs<'_, Self>, ) -> Result { let (token_address, gas_limit) = match &self.coin_type { - // TODO need new consts and params for v2 calls - EthCoinType::Eth => (Address::default(), self.gas_limit.eth_sender_refund), + EthCoinType::Eth => (Address::default(), self.gas_limit_v2.taker.eth_taker_refund_secret), EthCoinType::Erc20 { platform: _, token_addr, - } => (*token_addr, self.gas_limit.erc20_sender_refund), + } => (*token_addr, self.gas_limit_v2.taker.erc20_taker_refund_secret), EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( "NFT protocol is not supported for ETH and ERC20 Swaps" @@ -406,10 +401,9 @@ impl EthCoin { gen_args: &GenTakerPaymentSpendArgs<'_, Self>, secret: &[u8], ) -> Result { - // TODO need new consts and params for v2 calls let gas_limit = match self.coin_type { - EthCoinType::Eth => U256::from(self.gas_limit.eth_receiver_spend), - EthCoinType::Erc20 { .. } => U256::from(self.gas_limit.erc20_receiver_spend), + EthCoinType::Eth => U256::from(self.gas_limit_v2.taker.eth_maker_spend), + EthCoinType::Erc20 { .. } => U256::from(self.gas_limit_v2.taker.erc20_maker_spend), EthCoinType::Nft { .. } => { return Err(TransactionErr::ProtocolNotSupported(ERRL!( "NFT protocol is not supported for ETH and ERC20 Swaps" diff --git a/mm2src/coins/eth/for_tests.rs b/mm2src/coins/eth/for_tests.rs index d3b8ece3ac..cc6d5cd375 100644 --- a/mm2src/coins/eth/for_tests.rs +++ b/mm2src/coins/eth/for_tests.rs @@ -50,7 +50,8 @@ pub(crate) fn eth_coin_from_keypair( }; let my_address = key_pair.address(); let coin_conf = coin_conf(&ctx, &ticker); - let gas_limit = extract_gas_limit_from_conf(&coin_conf).expect("expected valid gas_limit config"); + let gas_limit: EthGasLimit = extract_gas_limit_from_conf(&coin_conf).expect("expected valid gas_limit config"); + let gas_limit_v2: EthGasLimitV2 = extract_gas_limit_from_conf(&coin_conf).expect("expected valid gas_limit config"); let eth_coin = EthCoin(Arc::new(EthCoinImpl { coin_type, @@ -77,6 +78,7 @@ pub(crate) fn eth_coin_from_keypair( nfts_infos: Arc::new(Default::default()), platform_fee_estimator_state: Arc::new(FeeEstimatorState::CoinNotSupported), gas_limit, + gas_limit_v2, abortable_system: AbortableQueue::default(), })); (ctx, eth_coin) diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index 15af41b3c2..307b382e49 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -417,7 +417,9 @@ impl EthCoin { }; let platform_fee_estimator_state = FeeEstimatorState::init_fee_estimator(&ctx, &conf, &coin_type).await?; let max_eth_tx_type = get_max_eth_tx_type_conf(&ctx, &conf, &coin_type).await?; - let gas_limit = extract_gas_limit_from_conf(&conf) + let gas_limit: EthGasLimit = extract_gas_limit_from_conf(&conf) + .map_to_mm(|e| EthTokenActivationError::InternalError(format!("invalid gas_limit config {}", e)))?; + let gas_limit_v2: EthGasLimitV2 = extract_gas_limit_from_conf(&conf) .map_to_mm(|e| EthTokenActivationError::InternalError(format!("invalid gas_limit config {}", e)))?; let token = EthCoinImpl { @@ -448,6 +450,7 @@ impl EthCoin { nfts_infos: Default::default(), platform_fee_estimator_state, gas_limit, + gas_limit_v2, abortable_system, }; @@ -506,7 +509,9 @@ impl EthCoin { }; let platform_fee_estimator_state = FeeEstimatorState::init_fee_estimator(&ctx, &conf, &coin_type).await?; let max_eth_tx_type = get_max_eth_tx_type_conf(&ctx, &conf, &coin_type).await?; - let gas_limit = extract_gas_limit_from_conf(&conf) + let gas_limit: EthGasLimit = extract_gas_limit_from_conf(&conf) + .map_to_mm(|e| EthTokenActivationError::InternalError(format!("invalid gas_limit config {}", e)))?; + let gas_limit_v2: EthGasLimitV2 = extract_gas_limit_from_conf(&conf) .map_to_mm(|e| EthTokenActivationError::InternalError(format!("invalid gas_limit config {}", e)))?; let global_nft = EthCoinImpl { @@ -534,6 +539,7 @@ impl EthCoin { nfts_infos: Arc::new(AsyncMutex::new(nft_infos)), platform_fee_estimator_state, gas_limit, + gas_limit_v2, abortable_system, }; Ok(EthCoin(Arc::new(global_nft))) @@ -639,7 +645,9 @@ pub async fn eth_coin_from_conf_and_request_v2( let coin_type = EthCoinType::Eth; let platform_fee_estimator_state = FeeEstimatorState::init_fee_estimator(ctx, conf, &coin_type).await?; let max_eth_tx_type = get_max_eth_tx_type_conf(ctx, conf, &coin_type).await?; - let gas_limit = extract_gas_limit_from_conf(conf) + let gas_limit: EthGasLimit = extract_gas_limit_from_conf(conf) + .map_to_mm(|e| EthActivationV2Error::InternalError(format!("invalid gas_limit config {}", e)))?; + let gas_limit_v2: EthGasLimitV2 = extract_gas_limit_from_conf(conf) .map_to_mm(|e| EthActivationV2Error::InternalError(format!("invalid gas_limit config {}", e)))?; let coin = EthCoinImpl { @@ -667,6 +675,7 @@ pub async fn eth_coin_from_conf_and_request_v2( nfts_infos: Default::default(), platform_fee_estimator_state, gas_limit, + gas_limit_v2, abortable_system, }; From ce7903dea78af942379ce1b584881c680dd50127 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 10 Sep 2024 16:17:58 +0700 Subject: [PATCH 14/38] taker gas limits v2 --- mm2src/coins/eth.rs | 6 ++-- .../tests/docker_tests/eth_docker_tests.rs | 28 +++++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index fa157ae28c..c1b2a1cb58 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -251,9 +251,9 @@ pub mod gas_limit { pub const ETH_MAX_TRADE_GAS: u64 = 150_000; } -/// Gas limits for EthGasLimitV2 +/// Default gas limits for EthGasLimitV2 pub mod gas_limit_v2 { - /// Gas limits for maker operations in EthGasLimitV2 + /// Gas limits for maker operations in EtomicSwapMakerV2 contract pub mod maker { pub const ETH_SEND_PAYMENT: u64 = 65_000; pub const ERC20_SEND_PAYMENT: u64 = 115_000; @@ -265,7 +265,7 @@ pub mod gas_limit_v2 { pub const ERC20_MAKER_REFUND_SECRET: u64 = 65_000; } - /// Gas limits for taker operations in EthGasLimitV2 + /// Gas limits for taker operations in EtomicSwapTakerV2 contract pub mod taker { pub const ETH_SEND_PAYMENT: u64 = 65_000; pub const ERC20_SEND_PAYMENT: u64 = 115_000; 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 a4cd19a142..b387920fec 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1452,11 +1452,9 @@ fn eth_coin_v2_activation_with_random_privkey( coin } -#[ignore] #[test] fn send_and_refund_taker_funding_by_secret_eth() { // sepolia test - thread::sleep(Duration::from_secs(5)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1514,10 +1512,9 @@ fn send_and_refund_taker_funding_by_secret_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] #[test] fn send_and_refund_taker_funding_by_secret_erc20() { - thread::sleep(Duration::from_secs(130)); + thread::sleep(Duration::from_secs(30)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -1576,11 +1573,10 @@ fn send_and_refund_taker_funding_by_secret_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 200); } -#[ignore] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { - thread::sleep(Duration::from_secs(12)); // sepolia test + thread::sleep(Duration::from_secs(60)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1641,10 +1637,10 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] #[test] fn taker_send_approve_and_spend_eth() { // sepolia test + thread::sleep(Duration::from_secs(90)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1750,11 +1746,10 @@ fn taker_send_approve_and_spend_eth() { block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } -#[ignore] #[test] fn taker_send_approve_and_spend_erc20() { // sepolia test - thread::sleep(Duration::from_secs(9)); + thread::sleep(Duration::from_secs(120)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -1860,11 +1855,10 @@ fn taker_send_approve_and_spend_erc20() { block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } -#[ignore] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { // sepolia test - thread::sleep(Duration::from_secs(25)); + thread::sleep(Duration::from_secs(150)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1944,11 +1938,10 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { // sepolia test - thread::sleep(Duration::from_secs(28)); + thread::sleep(Duration::from_secs(180)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2030,11 +2023,10 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { // sepolia test - thread::sleep(Duration::from_secs(200)); + thread::sleep(Duration::from_secs(210)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2097,6 +2089,7 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 150); } +#[ignore] #[test] fn send_maker_payment_and_refund_timelock_eth() { thread::sleep(Duration::from_secs(150)); @@ -2149,6 +2142,7 @@ fn send_maker_payment_and_refund_timelock_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[ignore] #[test] fn send_maker_payment_and_refund_timelock_erc20() { thread::sleep(Duration::from_secs(120)); @@ -2202,6 +2196,7 @@ fn send_maker_payment_and_refund_timelock_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[ignore] #[test] fn send_maker_payment_and_refund_secret_eth() { thread::sleep(Duration::from_secs(90)); @@ -2251,6 +2246,7 @@ fn send_maker_payment_and_refund_secret_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[ignore] #[test] fn send_maker_payment_and_refund_secret_erc20() { thread::sleep(Duration::from_secs(60)); @@ -2301,6 +2297,7 @@ fn send_maker_payment_and_refund_secret_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[ignore] #[test] fn send_and_spend_maker_payment_eth() { let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2362,6 +2359,7 @@ fn send_and_spend_maker_payment_eth() { block_on(maker_coin.wait_for_maker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } +#[ignore] #[test] fn send_and_spend_maker_payment_erc20() { thread::sleep(Duration::from_secs(30)); From f1063c7216fe753289fefb3e12c8316858b2b8cc Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 10 Sep 2024 20:03:46 +0700 Subject: [PATCH 15/38] move prepare erc20 payment data above allowance, impl handle_allowance --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 22 ++------- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 46 ++++++------------- mm2src/coins/eth/eth_swap_v2/mod.rs | 34 +++++++++++++- 3 files changed, 50 insertions(+), 52 deletions(-) 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 fb9446b88b..1f010ddafa 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 @@ -3,7 +3,7 @@ use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, - SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, Transaction, TransactionErr, ValidateMakerPaymentArgs, + SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, TransactionErr, ValidateMakerPaymentArgs, WaitForPaymentSpendError}; use common::executor::Timer; use common::now_sec; @@ -82,28 +82,12 @@ impl EthCoin { platform: _, token_addr, } => { - let allowed = self - .allowance(maker_swap_v2_contract) - .compat() - .await - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let data = try_tx_s!( self.prepare_maker_erc20_payment_data(&payment_args, payment_amount, *token_addr) .await ); - if allowed < payment_amount { - let approved_tx = self.approve(maker_swap_v2_contract, U256::max_value()).compat().await?; - self.wait_for_required_allowance(maker_swap_v2_contract, payment_amount, args.time_lock) - .compat() - .await - .map_err(|e| { - TransactionErr::Plain(ERRL!( - "Allowed value was not updated in time after sending approve transaction {:02x}: {}", - approved_tx.tx_hash_as_bytes(), - e - )) - })?; - } + self.handle_allowance(maker_swap_v2_contract, payment_amount, args.time_lock) + .await?; self.sign_and_send_transaction( U256::from(ZERO_VALUE), Action::Call(maker_swap_v2_contract), 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 126f8a00d5..ffda7626dc 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 @@ -2,8 +2,8 @@ use super::{check_decoded_length, validate_from_to_and_status, validate_payment_ EthPaymentType, PrepareTxDataError, ZERO_VALUE}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, - SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, Transaction, TransactionErr, - ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; + SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, TransactionErr, ValidateSwapV2TxError, + ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; use crate::{FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, SearchForFundingSpendErr, WaitForPaymentSpendError}; use common::executor::Timer; @@ -42,6 +42,17 @@ struct TakerRefundArgs { token_address: Address, } +struct TakerValidationArgs<'a> { + swap_id: Vec, + amount: U256, + dex_fee: U256, + receiver: Address, + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + funding_time_lock: u64, + payment_time_lock: u64, +} + impl EthCoin { /// Calls `"ethTakerPayment"` or `"erc20TakerPayment"` swap contract methods. /// Returns taker sent payment transaction. @@ -92,25 +103,9 @@ impl EthCoin { platform: _, token_addr, } => { - let allowed = self - .allowance(taker_swap_v2_contract) - .compat() - .await - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let data = try_tx_s!(self.prepare_taker_erc20_funding_data(&funding_args, *token_addr).await); - if allowed < payment_amount { - let approved_tx = self.approve(taker_swap_v2_contract, U256::max_value()).compat().await?; - self.wait_for_required_allowance(taker_swap_v2_contract, payment_amount, args.funding_time_lock) - .compat() - .await - .map_err(|e| { - TransactionErr::Plain(ERRL!( - "Allowed value was not updated in time after sending approve transaction {:02x}: {}", - approved_tx.tx_hash_as_bytes(), - e - )) - })?; - } + self.handle_allowance(taker_swap_v2_contract, payment_amount, args.funding_time_lock) + .await?; self.sign_and_send_transaction( U256::from(ZERO_VALUE), Action::Call(taker_swap_v2_contract), @@ -683,17 +678,6 @@ impl EthCoin { } } -struct TakerValidationArgs<'a> { - swap_id: Vec, - amount: U256, - dex_fee: U256, - receiver: Address, - taker_secret_hash: &'a [u8], - maker_secret_hash: &'a [u8], - funding_time_lock: u64, - payment_time_lock: u64, -} - /// Validation function for ETH taker payment data fn validate_eth_taker_payment_data( decoded: &[Token], diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index 52e2137a93..1591452af4 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -1,9 +1,9 @@ -use crate::eth::EthCoin; -use crate::ParseCoinAssocTypes; +use crate::eth::{EthCoin, ParseCoinAssocTypes, Transaction, TransactionErr}; use enum_derives::EnumFromStringify; use ethabi::{Contract, Token}; use ethcore_transaction::SignedTransaction as SignedEthTx; use ethereum_types::{Address, U256}; +use futures::compat::Future01CompatExt; use mm2_err_handle::mm_error::MmError; use mm2_number::BigDecimal; use web3::types::Transaction as Web3Tx; @@ -169,3 +169,33 @@ fn check_decoded_length(decoded: &Vec, expected_len: usize) -> Result<(), } Ok(()) } + +impl EthCoin { + async fn handle_allowance( + &self, + swap_contract: Address, + payment_amount: U256, + time_lock: u64, + ) -> Result<(), TransactionErr> { + let allowed = self + .allowance(swap_contract) + .compat() + .await + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + + if allowed < payment_amount { + let approved_tx = self.approve(swap_contract, U256::max_value()).compat().await?; + self.wait_for_required_allowance(swap_contract, payment_amount, time_lock) + .compat() + .await + .map_err(|e| { + TransactionErr::Plain(ERRL!( + "Allowed value was not updated in time after sending approve transaction {:02x}: {}", + approved_tx.tx_hash_as_bytes(), + e + )) + })?; + } + Ok(()) + } +} From 60f11f8c0d7fbeae1802012e5d27aabef68be854 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 10 Sep 2024 20:52:48 +0700 Subject: [PATCH 16/38] start using `nft_maker_swap_v2_contract` from EthCoin in Nft maker swap ops, remove `swap_contract_addres` from NFT swap args --- mm2src/coins/eth/nft_swap_v2/mod.rs | 68 ++++++++++++++----- mm2src/coins/eth/nft_swap_v2/structs.rs | 2 +- mm2src/coins/lp_coins.rs | 6 -- .../tests/docker_tests/eth_docker_tests.rs | 8 +-- 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 6f6a8965fd..2c173d15c9 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -58,6 +58,15 @@ impl EthCoin { ) -> ValidatePaymentResult<()> { match self.coin_type { EthCoinType::Nft { .. } => { + let nft_maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.nft_maker_swap_v2_contract) + .ok_or_else(|| { + ValidatePaymentError::InternalError( + "Expected swap_v2_contracts to be Some, but found None".to_string(), + ) + })?; let contract_type = args.nft_swap_info.contract_type; validate_payment_args( args.taker_secret_hash, @@ -66,14 +75,12 @@ impl EthCoin { contract_type, ) .map_err(ValidatePaymentError::InternalError)?; - // TODO use swap contract address from self - let etomic_swap_contract = args.nft_swap_info.swap_contract_address; let token_address = args.nft_swap_info.token_address; let maker_address = public_to_address(args.maker_pub); let swap_id = self.etomic_swap_id_v2(args.time_lock, args.maker_secret_hash); let maker_status = self .payment_status_v2( - *etomic_swap_contract, + nft_maker_swap_v2_contract, Token::FixedBytes(swap_id.clone()), &NFT_MAKER_SWAP_V2, EthPaymentType::MakerPayments, @@ -107,7 +114,7 @@ impl EthCoin { let validation_params = ValidationParams { maker_address, - etomic_swap_contract: *etomic_swap_contract, + nft_maker_swap_v2_contract, token_id: args.nft_swap_info.token_id, amount, }; @@ -139,7 +146,13 @@ impl EthCoin { ) -> Result { match self.coin_type { EthCoinType::Nft { .. } => { - let etomic_swap_contract = args.swap_contract_address; + let nft_maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.nft_maker_swap_v2_contract) + .ok_or_else(|| { + TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")) + })?; if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } @@ -150,7 +163,7 @@ impl EthCoin { let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( - *etomic_swap_contract, + nft_maker_swap_v2_contract, &NFT_MAKER_SWAP_V2, &decoded, bytes_index, @@ -162,7 +175,7 @@ impl EthCoin { let data = try_tx_s!(self.prepare_spend_nft_maker_v2_data(&args, decoded, htlc_params, state)); self.sign_and_send_transaction( ZERO_VALUE.into(), - Action::Call(*etomic_swap_contract), + Action::Call(nft_maker_swap_v2_contract), data, U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value ) @@ -181,7 +194,13 @@ impl EthCoin { ) -> Result { match self.coin_type { EthCoinType::Nft { .. } => { - let etomic_swap_contract = args.swap_contract_address; + let nft_maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.nft_maker_swap_v2_contract) + .ok_or_else(|| { + TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")) + })?; let (decoded, bytes_index) = try_tx_s!(get_decoded_tx_data_and_bytes_index( args.contract_type, args.maker_payment_tx.unsigned().data() @@ -189,7 +208,7 @@ impl EthCoin { let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( - *etomic_swap_contract, + nft_maker_swap_v2_contract, &NFT_MAKER_SWAP_V2, &decoded, bytes_index, @@ -202,7 +221,7 @@ impl EthCoin { try_tx_s!(self.prepare_refund_nft_maker_payment_v2_timelock(&args, decoded, htlc_params, state)); self.sign_and_send_transaction( ZERO_VALUE.into(), - Action::Call(*etomic_swap_contract), + Action::Call(nft_maker_swap_v2_contract), data, U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value ) @@ -221,7 +240,13 @@ impl EthCoin { ) -> Result { match self.coin_type { EthCoinType::Nft { .. } => { - let etomic_swap_contract = args.swap_contract_address; + let nft_maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.nft_maker_swap_v2_contract) + .ok_or_else(|| { + TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")) + })?; let (decoded, bytes_index) = try_tx_s!(get_decoded_tx_data_and_bytes_index( args.contract_type, args.maker_payment_tx.unsigned().data() @@ -229,7 +254,7 @@ impl EthCoin { let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( - *etomic_swap_contract, + nft_maker_swap_v2_contract, &NFT_MAKER_SWAP_V2, &decoded, bytes_index, @@ -243,7 +268,7 @@ impl EthCoin { try_tx_s!(self.prepare_refund_nft_maker_payment_v2_secret(&args, decoded, htlc_params, state)); self.sign_and_send_transaction( ZERO_VALUE.into(), - Action::Call(*etomic_swap_contract), + Action::Call(nft_maker_swap_v2_contract), data, U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value ) @@ -261,6 +286,13 @@ impl EthCoin { args: &SendNftMakerPaymentArgs<'_, Self>, htlc_data: Vec, ) -> Result, PrepareTxDataError> { + let nft_maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.nft_maker_swap_v2_contract) + .ok_or_else(|| { + PrepareTxDataError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) + })?; match args.nft_swap_info.contract_type { ContractType::Erc1155 => { let function = ERC1155_CONTRACT.function("safeTransferFrom")?; @@ -268,7 +300,7 @@ impl EthCoin { .map_err(|e| PrepareTxDataError::Internal(e.to_string()))?; let data = function.encode_input(&[ Token::Address(self.my_addr().await), - Token::Address(*args.nft_swap_info.swap_contract_address), + Token::Address(nft_maker_swap_v2_contract), Token::Uint(U256::from(args.nft_swap_info.token_id)), Token::Uint(amount_u256), Token::Bytes(htlc_data), @@ -279,7 +311,7 @@ impl EthCoin { let function = erc721_transfer_with_data()?; let data = function.encode_input(&[ Token::Address(self.my_addr().await), - Token::Address(*args.nft_swap_info.swap_contract_address), + Token::Address(nft_maker_swap_v2_contract), Token::Uint(U256::from(args.nft_swap_info.token_id)), Token::Bytes(htlc_data), ])?; @@ -438,7 +470,11 @@ impl EthCoin { fn validate_decoded_data(decoded: &[Token], params: &ValidationParams) -> Result<(), MmError> { let checks = vec![ (0, Token::Address(params.maker_address), "maker_address"), - (1, Token::Address(params.etomic_swap_contract), "etomic_swap_contract"), + ( + 1, + Token::Address(params.nft_maker_swap_v2_contract), + "nft_maker_swap_v2_contract", + ), (2, Token::Uint(U256::from(params.token_id)), "token_id"), ]; diff --git a/mm2src/coins/eth/nft_swap_v2/structs.rs b/mm2src/coins/eth/nft_swap_v2/structs.rs index 2866d81a01..7bd4130d9f 100644 --- a/mm2src/coins/eth/nft_swap_v2/structs.rs +++ b/mm2src/coins/eth/nft_swap_v2/structs.rs @@ -11,7 +11,7 @@ pub(crate) struct ExpectedHtlcParams { pub(crate) struct ValidationParams<'a> { pub(crate) maker_address: Address, - pub(crate) etomic_swap_contract: Address, + pub(crate) nft_maker_swap_v2_contract: Address, pub(crate) token_id: &'a [u8], // Optional, as it's not needed for ERC721 pub(crate) amount: Option, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index aedb4a8cdf..2062133433 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1650,8 +1650,6 @@ pub struct NftSwapInfo<'a, Coin: ParseNftAssocTypes + ?Sized> { pub token_id: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a Coin::ContractType, - /// Etomic swap contract address - pub swap_contract_address: &'a Coin::ContractAddress, } pub struct SendNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftAssocTypes + ?Sized> { @@ -1742,8 +1740,6 @@ pub struct RefundNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftAss pub swap_unique_data: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a Coin::ContractType, - /// Etomic swap contract address - pub swap_contract_address: &'a Coin::ContractAddress, } pub struct SpendMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { @@ -1779,8 +1775,6 @@ pub struct SpendNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftAsso pub swap_unique_data: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a Coin::ContractType, - /// Etomic swap contract address - pub swap_contract_address: &'a Coin::ContractAddress, } /// Operations specific to maker coin in [Trading Protocol Upgrade implementation](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1895) 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 b387920fec..3c00cd3045 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1198,9 +1198,8 @@ pub struct TestNftSwapInfo { pub token_id: Vec, /// The type of smart contract that governs this NFT pub contract_type: Coin::ContractType, - /// Etomic swap contract address - pub swap_contract_address: Coin::ContractAddress, } + struct NftActivationV2Args { swap_contract_address: Address, fallback_swap_contract_address: Address, @@ -1268,7 +1267,6 @@ fn setup_test( token_address: token_contract, token_id, contract_type, - swap_contract_address: activation.swap_v2_contracts.nft_maker_swap_v2_contract, }; NftTestSetup { @@ -1288,7 +1286,6 @@ fn send_nft_maker_payment(setup: &NftTestSetup, amount: BigDecimal) -> SignedEth token_address: &setup.nft_swap_info.token_address, token_id: &setup.nft_swap_info.token_id, contract_type: &setup.nft_swap_info.contract_type, - swap_contract_address: &setup.nft_swap_info.swap_contract_address, }; let send_payment_args = SendNftMakerPaymentArgs:: { time_lock: setup.time_lock, @@ -1318,7 +1315,6 @@ fn validate_nft_maker_payment(setup: &NftTestSetup, maker_payment: &SignedEthTx, token_address: &setup.nft_swap_info.token_address, token_id: &setup.nft_swap_info.token_id, contract_type: &setup.nft_swap_info.contract_type, - swap_contract_address: &setup.nft_swap_info.swap_contract_address, }; let validate_args = ValidateNftMakerPaymentArgs { maker_payment_tx: maker_payment, @@ -1347,7 +1343,6 @@ fn spend_nft_maker_payment( maker_pub: &setup.maker_global_nft.derive_htlc_pubkey_v2(&[]), swap_unique_data: &[], contract_type, - swap_contract_address: &setup.nft_swap_info.swap_contract_address, }; block_on(setup.taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap() } @@ -1365,7 +1360,6 @@ fn refund_nft_maker_payment( taker_secret: &setup.taker_secret, swap_unique_data: &[], contract_type, - swap_contract_address: &setup.nft_swap_info.swap_contract_address, }; match refund_type { RefundType::Timelock => { From 0c9699203e0b2a80ec48f90723cdaca165a53f08 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 11 Sep 2024 18:09:15 +0700 Subject: [PATCH 17/38] nft maker gas limits v2 --- mm2src/coins/eth.rs | 42 ++++++++++++++++++++++++++++- mm2src/coins/eth/nft_swap_v2/mod.rs | 24 ++++++++++++++--- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index c1b2a1cb58..133cf76641 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -269,7 +269,7 @@ pub mod gas_limit_v2 { pub mod taker { pub const ETH_SEND_PAYMENT: u64 = 65_000; pub const ERC20_SEND_PAYMENT: u64 = 115_000; - pub const ETH_MAKER_SPEND: u64 = 65_000; + pub const ETH_MAKER_SPEND: u64 = 100_000; pub const ERC20_MAKER_SPEND: u64 = 115_000; pub const ETH_TAKER_REFUND_TIMELOCK: u64 = 65_000; pub const ERC20_TAKER_REFUND_TIMELOCK: u64 = 70_000; @@ -277,6 +277,17 @@ pub mod gas_limit_v2 { pub const ERC20_TAKER_REFUND_SECRET: u64 = 70_000; pub const APPROVE_PAYMENT: u64 = 50_000; } + + pub mod nft_maker { + pub const ERC721_SEND_PAYMENT: u64 = 130_000; + pub const ERC1155_SEND_PAYMENT: u64 = 130_000; + pub const ERC721_TAKER_SPEND: u64 = 100_000; + pub const ERC1155_TAKER_SPEND: u64 = 100_000; + pub const ERC721_MAKER_REFUND_TIMELOCK: u64 = 100_000; + pub const ERC1155_MAKER_REFUND_TIMELOCK: u64 = 100_000; + pub const ERC721_MAKER_REFUND_SECRET: u64 = 100_000; + pub const ERC1155_MAKER_REFUND_SECRET: u64 = 100_000; + } } /// Coin conf param to override default gas limits @@ -324,6 +335,7 @@ impl Default for EthGasLimit { pub struct EthGasLimitV2 { pub maker: MakerGasLimitV2, pub taker: TakerGasLimitV2, + pub nft_maker: NftMakerGasLimitV2, } #[derive(Deserialize)] @@ -353,6 +365,19 @@ pub struct TakerGasLimitV2 { pub approve_payment: u64, } +#[derive(Deserialize)] +#[serde(default)] +pub struct NftMakerGasLimitV2 { + pub erc721_send_payment: u64, + pub erc1155_send_payment: u64, + pub erc721_taker_spend: u64, + pub erc1155_taker_spend: u64, + pub erc721_maker_refund_timelock: u64, + pub erc1155_maker_refund_timelock: u64, + pub erc721_maker_refund_secret: u64, + pub erc1155_maker_refund_secret: u64, +} + impl Default for MakerGasLimitV2 { fn default() -> Self { MakerGasLimitV2 { @@ -384,6 +409,21 @@ impl Default for TakerGasLimitV2 { } } +impl Default for NftMakerGasLimitV2 { + fn default() -> Self { + NftMakerGasLimitV2 { + erc721_send_payment: gas_limit_v2::nft_maker::ERC721_SEND_PAYMENT, + erc1155_send_payment: gas_limit_v2::nft_maker::ERC1155_SEND_PAYMENT, + erc721_taker_spend: gas_limit_v2::nft_maker::ERC721_TAKER_SPEND, + erc1155_taker_spend: gas_limit_v2::nft_maker::ERC1155_TAKER_SPEND, + erc721_maker_refund_timelock: gas_limit_v2::nft_maker::ERC721_MAKER_REFUND_TIMELOCK, + erc1155_maker_refund_timelock: gas_limit_v2::nft_maker::ERC1155_MAKER_REFUND_TIMELOCK, + erc721_maker_refund_secret: gas_limit_v2::nft_maker::ERC721_MAKER_REFUND_SECRET, + erc1155_maker_refund_secret: gas_limit_v2::nft_maker::ERC1155_MAKER_REFUND_SECRET, + } + } +} + trait ExtractGasLimit: Default + for<'de> Deserialize<'de> { fn key() -> &'static str; } diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 2c173d15c9..8277cc8bf5 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -37,11 +37,15 @@ impl EthCoin { let htlc_data = try_tx_s!(self.prepare_htlc_data(&args)); let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data(&args, htlc_data).await); + let gas_limit = match args.nft_swap_info.contract_type { + ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_send_payment, + ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_send_payment, + }; self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(*args.nft_swap_info.token_address), data, - U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value + U256::from(gas_limit), ) .compat() .await @@ -173,11 +177,15 @@ impl EthCoin { .await ); let data = try_tx_s!(self.prepare_spend_nft_maker_v2_data(&args, decoded, htlc_params, state)); + let gas_limit = match args.contract_type { + ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_taker_spend, + ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_taker_spend, + }; self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(nft_maker_swap_v2_contract), data, - U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value + U256::from(gas_limit), ) .compat() .await @@ -219,11 +227,15 @@ impl EthCoin { ); let data = try_tx_s!(self.prepare_refund_nft_maker_payment_v2_timelock(&args, decoded, htlc_params, state)); + let gas_limit = match args.contract_type { + ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_maker_refund_timelock, + ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_maker_refund_timelock, + }; self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(nft_maker_swap_v2_contract), data, - U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value + U256::from(gas_limit), ) .compat() .await @@ -266,11 +278,15 @@ impl EthCoin { let data = try_tx_s!(self.prepare_refund_nft_maker_payment_v2_secret(&args, decoded, htlc_params, state)); + let gas_limit = match args.contract_type { + ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_maker_refund_secret, + ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_maker_refund_secret, + }; self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(nft_maker_swap_v2_contract), data, - U256::from(self.gas_limit.eth_max_trade_gas), // TODO: fix to a more accurate const or estimated value + U256::from(gas_limit), ) .compat() .await From 8f983ec362cb00704b27582b8c0dc3e9934aa912 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 11 Sep 2024 18:20:24 +0700 Subject: [PATCH 18/38] update taker time --- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 3c00cd3045..f4cd7c31c3 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1634,7 +1634,7 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { #[test] fn taker_send_approve_and_spend_eth() { // sepolia test - thread::sleep(Duration::from_secs(90)); + thread::sleep(Duration::from_secs(100)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1743,7 +1743,7 @@ fn taker_send_approve_and_spend_eth() { #[test] fn taker_send_approve_and_spend_erc20() { // sepolia test - thread::sleep(Duration::from_secs(120)); + thread::sleep(Duration::from_secs(130)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -1852,7 +1852,7 @@ fn taker_send_approve_and_spend_erc20() { #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { // sepolia test - thread::sleep(Duration::from_secs(150)); + thread::sleep(Duration::from_secs(160)); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1935,7 +1935,7 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { // sepolia test - thread::sleep(Duration::from_secs(180)); + thread::sleep(Duration::from_secs(190)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2020,7 +2020,7 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { // sepolia test - thread::sleep(Duration::from_secs(210)); + thread::sleep(Duration::from_secs(220)); let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); From 6961d503f79b12015cc675b9dfc53d15d1964738 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 16 Sep 2024 14:09:05 +0700 Subject: [PATCH 19/38] update gas limit fields names --- mm2src/coins/eth.rs | 36 +++++++++---------- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 4 +-- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 4 +-- mm2src/coins/eth/nft_swap_v2/mod.rs | 4 +-- .../tests/docker_tests/eth_docker_tests.rs | 14 ++++---- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 133cf76641..8107c90e52 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -255,8 +255,8 @@ pub mod gas_limit { pub mod gas_limit_v2 { /// Gas limits for maker operations in EtomicSwapMakerV2 contract pub mod maker { - pub const ETH_SEND_PAYMENT: u64 = 65_000; - pub const ERC20_SEND_PAYMENT: u64 = 115_000; + pub const ETH_PAYMENT: u64 = 65_000; + pub const ERC20_PAYMENT: u64 = 115_000; pub const ETH_TAKER_SPEND: u64 = 65_000; pub const ERC20_TAKER_SPEND: u64 = 65_000; pub const ETH_MAKER_REFUND_TIMELOCK: u64 = 65_000; @@ -267,8 +267,8 @@ pub mod gas_limit_v2 { /// Gas limits for taker operations in EtomicSwapTakerV2 contract pub mod taker { - pub const ETH_SEND_PAYMENT: u64 = 65_000; - pub const ERC20_SEND_PAYMENT: u64 = 115_000; + pub const ETH_PAYMENT: u64 = 65_000; + pub const ERC20_PAYMENT: u64 = 115_000; pub const ETH_MAKER_SPEND: u64 = 100_000; pub const ERC20_MAKER_SPEND: u64 = 115_000; pub const ETH_TAKER_REFUND_TIMELOCK: u64 = 65_000; @@ -279,8 +279,8 @@ pub mod gas_limit_v2 { } pub mod nft_maker { - pub const ERC721_SEND_PAYMENT: u64 = 130_000; - pub const ERC1155_SEND_PAYMENT: u64 = 130_000; + pub const ERC721_PAYMENT: u64 = 130_000; + pub const ERC1155_PAYMENT: u64 = 130_000; pub const ERC721_TAKER_SPEND: u64 = 100_000; pub const ERC1155_TAKER_SPEND: u64 = 100_000; pub const ERC721_MAKER_REFUND_TIMELOCK: u64 = 100_000; @@ -341,8 +341,8 @@ pub struct EthGasLimitV2 { #[derive(Deserialize)] #[serde(default)] pub struct MakerGasLimitV2 { - pub eth_send_payment: u64, - pub erc20_send_payment: u64, + pub eth_payment: u64, + pub erc20_payment: u64, pub eth_taker_spend: u64, pub erc20_taker_spend: u64, pub eth_maker_refund_timelock: u64, @@ -354,8 +354,8 @@ pub struct MakerGasLimitV2 { #[derive(Deserialize)] #[serde(default)] pub struct TakerGasLimitV2 { - pub eth_send_payment: u64, - pub erc20_send_payment: u64, + pub eth_payment: u64, + pub erc20_payment: u64, pub eth_maker_spend: u64, pub erc20_maker_spend: u64, pub eth_taker_refund_timelock: u64, @@ -368,8 +368,8 @@ pub struct TakerGasLimitV2 { #[derive(Deserialize)] #[serde(default)] pub struct NftMakerGasLimitV2 { - pub erc721_send_payment: u64, - pub erc1155_send_payment: u64, + pub erc721_payment: u64, + pub erc1155_payment: u64, pub erc721_taker_spend: u64, pub erc1155_taker_spend: u64, pub erc721_maker_refund_timelock: u64, @@ -381,8 +381,8 @@ pub struct NftMakerGasLimitV2 { impl Default for MakerGasLimitV2 { fn default() -> Self { MakerGasLimitV2 { - eth_send_payment: gas_limit_v2::maker::ETH_SEND_PAYMENT, - erc20_send_payment: gas_limit_v2::maker::ERC20_SEND_PAYMENT, + eth_payment: gas_limit_v2::maker::ETH_PAYMENT, + erc20_payment: gas_limit_v2::maker::ERC20_PAYMENT, eth_taker_spend: gas_limit_v2::maker::ETH_TAKER_SPEND, erc20_taker_spend: gas_limit_v2::maker::ERC20_TAKER_SPEND, eth_maker_refund_timelock: gas_limit_v2::maker::ETH_MAKER_REFUND_TIMELOCK, @@ -396,8 +396,8 @@ impl Default for MakerGasLimitV2 { impl Default for TakerGasLimitV2 { fn default() -> Self { TakerGasLimitV2 { - eth_send_payment: gas_limit_v2::taker::ETH_SEND_PAYMENT, - erc20_send_payment: gas_limit_v2::taker::ERC20_SEND_PAYMENT, + eth_payment: gas_limit_v2::taker::ETH_PAYMENT, + erc20_payment: gas_limit_v2::taker::ERC20_PAYMENT, eth_maker_spend: gas_limit_v2::taker::ETH_MAKER_SPEND, erc20_maker_spend: gas_limit_v2::taker::ERC20_MAKER_SPEND, eth_taker_refund_timelock: gas_limit_v2::taker::ETH_TAKER_REFUND_TIMELOCK, @@ -412,8 +412,8 @@ impl Default for TakerGasLimitV2 { impl Default for NftMakerGasLimitV2 { fn default() -> Self { NftMakerGasLimitV2 { - erc721_send_payment: gas_limit_v2::nft_maker::ERC721_SEND_PAYMENT, - erc1155_send_payment: gas_limit_v2::nft_maker::ERC1155_SEND_PAYMENT, + erc721_payment: gas_limit_v2::nft_maker::ERC721_PAYMENT, + erc1155_payment: gas_limit_v2::nft_maker::ERC1155_PAYMENT, erc721_taker_spend: gas_limit_v2::nft_maker::ERC721_TAKER_SPEND, erc1155_taker_spend: gas_limit_v2::nft_maker::ERC1155_TAKER_SPEND, erc721_maker_refund_timelock: gas_limit_v2::nft_maker::ERC721_MAKER_REFUND_TIMELOCK, 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 1f010ddafa..0313d1d7fc 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 @@ -73,7 +73,7 @@ impl EthCoin { payment_amount, Action::Call(maker_swap_v2_contract), data, - U256::from(self.gas_limit_v2.maker.eth_send_payment), + U256::from(self.gas_limit_v2.maker.eth_payment), ) .compat() .await @@ -92,7 +92,7 @@ impl EthCoin { U256::from(ZERO_VALUE), Action::Call(maker_swap_v2_contract), data, - U256::from(self.gas_limit_v2.maker.erc20_send_payment), + U256::from(self.gas_limit_v2.maker.erc20_payment), ) .compat() .await 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 ffda7626dc..56eb5dcf4e 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 @@ -94,7 +94,7 @@ impl EthCoin { eth_total_payment, Action::Call(taker_swap_v2_contract), data, - U256::from(self.gas_limit_v2.taker.eth_send_payment), + U256::from(self.gas_limit_v2.taker.eth_payment), ) .compat() .await @@ -110,7 +110,7 @@ impl EthCoin { U256::from(ZERO_VALUE), Action::Call(taker_swap_v2_contract), data, - U256::from(self.gas_limit_v2.taker.erc20_send_payment), + U256::from(self.gas_limit_v2.taker.erc20_payment), ) .compat() .await diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 8277cc8bf5..d6eea6cb50 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -38,8 +38,8 @@ impl EthCoin { let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data(&args, htlc_data).await); let gas_limit = match args.nft_swap_info.contract_type { - ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_send_payment, - ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_send_payment, + ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_payment, + ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_payment, }; self.sign_and_send_transaction( ZERO_VALUE.into(), 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 f4cd7c31c3..a9e429379e 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1446,6 +1446,7 @@ fn eth_coin_v2_activation_with_random_privkey( coin } +#[ignore] #[test] fn send_and_refund_taker_funding_by_secret_eth() { // sepolia test @@ -1506,6 +1507,7 @@ fn send_and_refund_taker_funding_by_secret_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } +#[ignore] #[test] fn send_and_refund_taker_funding_by_secret_erc20() { thread::sleep(Duration::from_secs(30)); @@ -1567,6 +1569,7 @@ fn send_and_refund_taker_funding_by_secret_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 200); } +#[ignore] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { // sepolia test @@ -1631,6 +1634,7 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } +#[ignore] #[test] fn taker_send_approve_and_spend_eth() { // sepolia test @@ -1740,6 +1744,7 @@ fn taker_send_approve_and_spend_eth() { block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } +#[ignore] #[test] fn taker_send_approve_and_spend_erc20() { // sepolia test @@ -1849,6 +1854,7 @@ fn taker_send_approve_and_spend_erc20() { block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } +#[ignore] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { // sepolia test @@ -1932,6 +1938,7 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } +#[ignore] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { // sepolia test @@ -2017,6 +2024,7 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } +#[ignore] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { // sepolia test @@ -2083,7 +2091,6 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 150); } -#[ignore] #[test] fn send_maker_payment_and_refund_timelock_eth() { thread::sleep(Duration::from_secs(150)); @@ -2136,7 +2143,6 @@ fn send_maker_payment_and_refund_timelock_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_maker_payment_and_refund_timelock_erc20() { thread::sleep(Duration::from_secs(120)); @@ -2190,7 +2196,6 @@ fn send_maker_payment_and_refund_timelock_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_maker_payment_and_refund_secret_eth() { thread::sleep(Duration::from_secs(90)); @@ -2240,7 +2245,6 @@ fn send_maker_payment_and_refund_secret_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_maker_payment_and_refund_secret_erc20() { thread::sleep(Duration::from_secs(60)); @@ -2291,7 +2295,6 @@ fn send_maker_payment_and_refund_secret_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } -#[ignore] #[test] fn send_and_spend_maker_payment_eth() { let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2353,7 +2356,6 @@ fn send_and_spend_maker_payment_eth() { block_on(maker_coin.wait_for_maker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } -#[ignore] #[test] fn send_and_spend_maker_payment_erc20() { thread::sleep(Duration::from_secs(30)); From 5d9d1def63fd295da66e008a55f00b32a922e39c Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 16 Sep 2024 15:08:49 +0700 Subject: [PATCH 20/38] add sepolia test features --- mm2src/mm2_main/Cargo.toml | 2 + .../tests/docker_tests/docker_tests_common.rs | 34 ++++++--- .../tests/docker_tests/eth_docker_tests.rs | 69 +++++++++++++------ 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index 60c3e9aa62..eb92730066 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -24,6 +24,8 @@ default = [] trezor-udp = ["crypto/trezor-udp"] # use for tests to connect to trezor emulator over udp run-device-tests = [] enable-sia = ["coins/enable-sia", "coins_activation/enable-sia"] +sepolia-maker-swap-v2-tests = [] +sepolia-taker-swap-v2-tests = [] [dependencies] async-std = { version = "1.5", features = ["unstable"] } 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 00a713bb62..024776c13d 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -41,10 +41,14 @@ use secp256k1::Secp256k1; pub use secp256k1::{PublicKey, SecretKey}; use serde_json::{self as json, Value as Json}; use std::process::{Command, Stdio}; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] +use std::str::FromStr; pub use std::{env, thread}; -use std::{path::PathBuf, str::FromStr, sync::Mutex, time::Duration}; +use std::{path::PathBuf, sync::Mutex, time::Duration}; use testcontainers::{clients::Cli, core::WaitFor, Container, GenericImage, RunnableImage}; -use web3::types::{Address as EthAddress, BlockId, BlockNumber, TransactionRequest}; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] +use web3::types::Address as EthAddress; +use web3::types::{BlockId, BlockNumber, TransactionRequest}; use web3::{transports::Http, Web3}; lazy_static! { @@ -65,9 +69,13 @@ lazy_static! { /// This approach addresses the `replacement transaction` issue, which occurs when different transactions share the same nonce. pub static ref MM_CTX1: MmArc = MmCtxBuilder::new().with_conf(json!({"use_trading_proto_v2": true})).into_mm_arc(); pub static ref GETH_WEB3: Web3 = Web3::new(Http::new(GETH_RPC_URL).unwrap()); - pub static ref SEPOLIA_WEB3: Web3 = Web3::new(Http::new(SEPOLIA_RPC_URL).unwrap()); // Mutex used to prevent nonce re-usage during funding addresses used in tests pub static ref GETH_NONCE_LOCK: Mutex<()> = Mutex::new(()); +} + +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] +lazy_static! { + pub static ref SEPOLIA_WEB3: Web3 = Web3::new(Http::new(SEPOLIA_RPC_URL).unwrap()); pub static ref SEPOLIA_NONCE_LOCK: Mutex<()> = Mutex::new(()); } @@ -79,6 +87,7 @@ pub static mut QTUM_CONF_PATH: Option = None; pub static mut GETH_ACCOUNT: H160Eth = H160Eth::zero(); /// ERC20 token address on Geth dev node pub static mut GETH_ERC20_CONTRACT: H160Eth = H160Eth::zero(); +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub static mut SEPOLIA_ERC20_CONTRACT: H160Eth = H160Eth::zero(); /// Swap contract address on Geth dev node pub static mut GETH_SWAP_CONTRACT: H160Eth = H160Eth::zero(); @@ -86,7 +95,9 @@ pub static mut GETH_SWAP_CONTRACT: H160Eth = H160Eth::zero(); pub static mut GETH_MAKER_SWAP_V2: H160Eth = H160Eth::zero(); /// Taker Swap V2 contract address on Geth dev node pub static mut GETH_TAKER_SWAP_V2: H160Eth = H160Eth::zero(); +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub static mut SEPOLIA_TAKER_SWAP_V2: H160Eth = H160Eth::zero(); +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub static mut SEPOLIA_MAKER_SWAP_V2: H160Eth = H160Eth::zero(); /// Swap contract (with watchers support) address on Geth dev node pub static mut GETH_WATCHERS_SWAP_CONTRACT: H160Eth = H160Eth::zero(); @@ -96,9 +107,11 @@ pub static mut GETH_ERC721_CONTRACT: H160Eth = H160Eth::zero(); pub static mut GETH_ERC1155_CONTRACT: H160Eth = H160Eth::zero(); /// NFT Maker Swap V2 contract address on Geth dev node pub static mut GETH_NFT_MAKER_SWAP_V2: H160Eth = H160Eth::zero(); +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] /// NFT Maker Swap V2 contract address on Sepolia testnet pub static mut SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2: H160Eth = H160Eth::zero(); pub static GETH_RPC_URL: &str = "http://127.0.0.1:8545"; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub static SEPOLIA_RPC_URL: &str = "https://ethereum-sepolia-rpc.publicnode.com"; pub const UTXO_ASSET_DOCKER_IMAGE: &str = "docker.io/artempikulin/testblockchain"; @@ -1583,12 +1596,15 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } - SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 = EthAddress::from_str("0x9eb88cd58605d8fb9b14652d6152727f7e95fb4d").unwrap(); - SEPOLIA_ERC20_CONTRACT = EthAddress::from_str("0xF7b5F8E8555EF7A743f24D3E974E23A3C6cB6638").unwrap(); - SEPOLIA_TAKER_SWAP_V2 = EthAddress::from_str("0x7Cc9F2c1c3B797D09B9d1CCd7FDcD2539a4b3874").unwrap(); - // deploy tx https://sepolia.etherscan.io/tx/0x6f743d79ecb806f5899a6a801083e33eba9e6f10726af0873af9f39883db7f11 - SEPOLIA_MAKER_SWAP_V2 = EthAddress::from_str("0xf9000589c66Df3573645B59c10aa87594Edc318F").unwrap(); - + #[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] + { + SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 = + EthAddress::from_str("0x9eb88cd58605d8fb9b14652d6152727f7e95fb4d").unwrap(); + SEPOLIA_ERC20_CONTRACT = EthAddress::from_str("0xF7b5F8E8555EF7A743f24D3E974E23A3C6cB6638").unwrap(); + SEPOLIA_TAKER_SWAP_V2 = EthAddress::from_str("0x7Cc9F2c1c3B797D09B9d1CCd7FDcD2539a4b3874").unwrap(); + // deploy tx https://sepolia.etherscan.io/tx/0x6f743d79ecb806f5899a6a801083e33eba9e6f10726af0873af9f39883db7f11 + SEPOLIA_MAKER_SWAP_V2 = EthAddress::from_str("0xf9000589c66Df3573645B59c10aa87594Edc318F").unwrap(); + } let alice_passphrase = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let alice_keypair = key_pair_from_seed(&alice_passphrase).unwrap(); let alice_eth_addr = addr_from_raw_pubkey(alice_keypair.public()).unwrap(); 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 a9e429379e..2baa47f24a 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1,8 +1,9 @@ use super::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC721_TEST_ABI, GETH_ACCOUNT, GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, GETH_ERC721_CONTRACT, GETH_MAKER_SWAP_V2, GETH_NFT_MAKER_SWAP_V2, GETH_NONCE_LOCK, GETH_RPC_URL, GETH_SWAP_CONTRACT, - GETH_TAKER_SWAP_V2, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX, MM_CTX1, - SEPOLIA_ERC20_CONTRACT, SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2, SEPOLIA_MAKER_SWAP_V2, + GETH_TAKER_SWAP_V2, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX, MM_CTX1}; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] +use super::docker_tests_common::{SEPOLIA_ERC20_CONTRACT, SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2, SEPOLIA_MAKER_SWAP_V2, SEPOLIA_NONCE_LOCK, SEPOLIA_RPC_URL, SEPOLIA_TAKER_SWAP_V2, SEPOLIA_WEB3}; use crate::common::Future01CompatExt; use bitcrypto::{dhash160, sha256}; @@ -11,32 +12,42 @@ use coins::eth::v2_activation::{eth_coin_from_conf_and_request_v2, EthActivation use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, EthCoinType, EthPrivKeyBuildPolicy, SignedEthTx, SwapV2Contracts, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; -use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CoinsContext, CommonSwapOpsV2, ConfirmPaymentInput, - DerivationMethod, DexFee, Eip1559Ops, FoundSwapTxSpend, FundingTxSpend, GenTakerFundingSpendArgs, - GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MakerNftSwapOpsV2, MarketCoinOps, MmCoinEnum, MmCoinStruct, - NftSwapInfo, ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, RefundFundingSecretArgs, - RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, RefundNftMakerPaymentArgs, - RefundPaymentArgs, RefundTakerPaymentArgs, SearchForSwapTxSpendInput, SendMakerPaymentArgs, - SendNftMakerPaymentArgs, SendPaymentArgs, SendTakerFundingArgs, SpendMakerPaymentArgs, - SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, - TakerCoinSwapOpsV2, ToBytes, Transaction, TxPreimageWithSig, ValidateMakerPaymentArgs, - ValidateNftMakerPaymentArgs, ValidateTakerFundingArgs}; +use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CommonSwapOpsV2, ConfirmPaymentInput, + DerivationMethod, Eip1559Ops, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, NftSwapInfo, + ParseCoinAssocTypes, ParseNftAssocTypes, PrivKeyBuildPolicy, RefundNftMakerPaymentArgs, RefundPaymentArgs, + SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, SendPaymentArgs, SpendNftMakerPaymentArgs, + SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, ToBytes, Transaction, + ValidateNftMakerPaymentArgs}; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] +use coins::{CoinsContext, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, + MakerCoinSwapOpsV2, MmCoinEnum, MmCoinStruct, RefundFundingSecretArgs, RefundMakerPaymentSecretArgs, + RefundMakerPaymentTimelockArgs, RefundTakerPaymentArgs, SendMakerPaymentArgs, SendTakerFundingArgs, + SpendMakerPaymentArgs, TakerCoinSwapOpsV2, TxPreimageWithSig, ValidateMakerPaymentArgs, + ValidateTakerFundingArgs}; use common::{block_on, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; use futures01::Future; +#[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::{erc20_dev_conf, eth_dev_conf, eth_sepolia_conf, nft_dev_conf, sepolia_erc20_dev_conf}; +use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf}; +#[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 serde_json::Value as Json; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] use std::str::FromStr; use std::thread; use std::time::Duration; use web3::contract::{Contract, Options}; use web3::ethabi::Token; -use web3::types::{Address, BlockNumber, TransactionRequest, H256}; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] +use web3::types::BlockNumber; +use web3::types::{Address, TransactionRequest, H256}; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] const SEPOLIA_MAKER_PRIV: &str = "6e2f3a6223b928a05a3a3622b0c3f3573d03663b704a61a6eb73326de0487928"; +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] const SEPOLIA_TAKER_PRIV: &str = "e0be82dca60ff7e4c6d6db339ac9e1ae249af081dba2110bddd281e711608f16"; const NFT_ETH: &str = "NFT_ETH"; const ETH: &str = "ETH"; @@ -58,7 +69,9 @@ pub fn maker_swap_v2() -> Address { unsafe { GETH_MAKER_SWAP_V2 } } /// /// GETH_TAKER_SWAP_V2 is set once during initialization before tests start pub fn taker_swap_v2() -> Address { unsafe { GETH_TAKER_SWAP_V2 } } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub fn sepolia_taker_swap_v2() -> Address { unsafe { SEPOLIA_TAKER_SWAP_V2 } } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub fn sepolia_maker_swap_v2() -> Address { unsafe { SEPOLIA_MAKER_SWAP_V2 } } /// # Safety /// @@ -72,9 +85,11 @@ pub fn watchers_swap_contract() -> Address { unsafe { GETH_WATCHERS_SWAP_CONTRAC /// /// GETH_ERC20_CONTRACT is set once during initialization before tests start pub fn erc20_contract() -> Address { unsafe { GETH_ERC20_CONTRACT } } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub fn sepolia_erc20_contract() -> Address { unsafe { SEPOLIA_ERC20_CONTRACT } } /// Return ERC20 dev token contract address in checksum format pub fn erc20_contract_checksum() -> String { checksum_address(&format!("{:02x}", erc20_contract())) } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] pub fn sepolia_erc20_contract_checksum() -> String { checksum_address(&format!("{:02x}", sepolia_erc20_contract())) } /// # Safety /// @@ -84,6 +99,7 @@ pub fn geth_erc721_contract() -> Address { unsafe { GETH_ERC721_CONTRACT } } /// /// GETH_ERC1155_CONTRACT is set once during initialization before tests start pub fn geth_erc1155_contract() -> Address { unsafe { GETH_ERC1155_CONTRACT } } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] /// # Safety /// /// SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 address is set once during initialization before tests start @@ -401,6 +417,7 @@ fn global_nft_with_random_privkey( global_nft } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] /// Can be used to generate coin from Sepolia Maker/Taker priv keys. fn sepolia_coin_from_privkey(ctx: &MmArc, secret: &'static str, ticker: &str, conf: &Json, erc20: bool) -> EthCoin { let swap_addr = SwapAddresses { @@ -461,6 +478,7 @@ fn sepolia_coin_from_privkey(ctx: &MmArc, secret: &'static str, ticker: &str, co coin } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] fn get_or_create_sepolia_coin(ctx: &MmArc, priv_key: &'static str, ticker: &str, conf: &Json, erc20: bool) -> EthCoin { match block_on(lp_coinfind(ctx, ticker)).unwrap() { None => sepolia_coin_from_privkey(ctx, priv_key, ticker, conf, erc20), @@ -861,6 +879,7 @@ fn send_and_spend_erc20_maker_payment_priority_fee() { send_and_spend_erc20_maker_payment_impl(SwapTxFeePolicy::Medium); } +#[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] /// Wait for all pending transactions for the given address to be confirmed fn wait_pending_transactions(wallet_address: Address) { let _guard = SEPOLIA_NONCE_LOCK.lock().unwrap(); @@ -1446,7 +1465,7 @@ fn eth_coin_v2_activation_with_random_privkey( coin } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_by_secret_eth() { // sepolia test @@ -1507,7 +1526,7 @@ fn send_and_refund_taker_funding_by_secret_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_by_secret_erc20() { thread::sleep(Duration::from_secs(30)); @@ -1569,7 +1588,7 @@ fn send_and_refund_taker_funding_by_secret_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 200); } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { // sepolia test @@ -1634,7 +1653,7 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn taker_send_approve_and_spend_eth() { // sepolia test @@ -1744,7 +1763,7 @@ fn taker_send_approve_and_spend_eth() { block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn taker_send_approve_and_spend_erc20() { // sepolia test @@ -1854,7 +1873,7 @@ fn taker_send_approve_and_spend_erc20() { block_on(taker_coin.wait_for_taker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { // sepolia test @@ -1938,7 +1957,7 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { // sepolia test @@ -2024,7 +2043,7 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 100); } -#[ignore] +#[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { // sepolia test @@ -2091,6 +2110,7 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { wait_for_confirmations(&taker_coin, &funding_tx_refund, 150); } +#[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_timelock_eth() { thread::sleep(Duration::from_secs(150)); @@ -2143,6 +2163,7 @@ fn send_maker_payment_and_refund_timelock_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_timelock_erc20() { thread::sleep(Duration::from_secs(120)); @@ -2196,6 +2217,7 @@ fn send_maker_payment_and_refund_timelock_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_secret_eth() { thread::sleep(Duration::from_secs(90)); @@ -2245,6 +2267,7 @@ fn send_maker_payment_and_refund_secret_eth() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_secret_erc20() { thread::sleep(Duration::from_secs(60)); @@ -2295,6 +2318,7 @@ fn send_maker_payment_and_refund_secret_erc20() { wait_for_confirmations(&maker_coin, &payment_tx_refund, 100); } +#[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_and_spend_maker_payment_eth() { let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2356,6 +2380,7 @@ fn send_and_spend_maker_payment_eth() { block_on(maker_coin.wait_for_maker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } +#[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_and_spend_maker_payment_erc20() { thread::sleep(Duration::from_secs(30)); From 1ef0f43799cb897dc1d19e928bc270c99f303009 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 19 Sep 2024 19:49:27 +0700 Subject: [PATCH 21/38] provide SEPOLIA_TESTS_LOCK --- .../tests/docker_tests/docker_tests_common.rs | 1 + .../tests/docker_tests/eth_docker_tests.rs | 51 +++++++++++-------- 2 files changed, 31 insertions(+), 21 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 024776c13d..99c1d80b1e 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -77,6 +77,7 @@ lazy_static! { lazy_static! { pub static ref SEPOLIA_WEB3: Web3 = Web3::new(Http::new(SEPOLIA_RPC_URL).unwrap()); pub static ref SEPOLIA_NONCE_LOCK: Mutex<()> = Mutex::new(()); + pub static ref SEPOLIA_TESTS_LOCK: Mutex<()> = Mutex::new(()); } pub static mut QICK_TOKEN_ADDRESS: Option = None; 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 2baa47f24a..da487e044d 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -4,7 +4,8 @@ use super::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC7 GETH_TAKER_SWAP_V2, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX, MM_CTX1}; #[cfg(any(feature = "sepolia-maker-swap-v2-tests", feature = "sepolia-taker-swap-v2-tests"))] use super::docker_tests_common::{SEPOLIA_ERC20_CONTRACT, SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2, SEPOLIA_MAKER_SWAP_V2, - SEPOLIA_NONCE_LOCK, SEPOLIA_RPC_URL, SEPOLIA_TAKER_SWAP_V2, SEPOLIA_WEB3}; + SEPOLIA_NONCE_LOCK, SEPOLIA_RPC_URL, SEPOLIA_TAKER_SWAP_V2, SEPOLIA_TESTS_LOCK, + SEPOLIA_WEB3}; use crate::common::Future01CompatExt; use bitcrypto::{dhash160, sha256}; use coins::eth::gas_limit::ETH_MAX_TRADE_GAS; @@ -1468,7 +1469,8 @@ fn eth_coin_v2_activation_with_random_privkey( #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_by_secret_eth() { - // sepolia test + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1529,7 +1531,8 @@ fn send_and_refund_taker_funding_by_secret_eth() { #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_by_secret_erc20() { - thread::sleep(Duration::from_secs(30)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -1591,8 +1594,8 @@ fn send_and_refund_taker_funding_by_secret_erc20() { #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { - // sepolia test - thread::sleep(Duration::from_secs(60)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1656,8 +1659,8 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_eth() { #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn taker_send_approve_and_spend_eth() { - // sepolia test - thread::sleep(Duration::from_secs(100)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1766,8 +1769,8 @@ fn taker_send_approve_and_spend_eth() { #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn taker_send_approve_and_spend_erc20() { - // sepolia test - thread::sleep(Duration::from_secs(130)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -1876,8 +1879,8 @@ fn taker_send_approve_and_spend_erc20() { #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { - // sepolia test - thread::sleep(Duration::from_secs(160)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -1960,8 +1963,8 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_eth() { #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { - // sepolia test - thread::sleep(Duration::from_secs(190)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2046,8 +2049,8 @@ fn send_and_refund_taker_funding_exceed_payment_timelock_erc20() { #[cfg(feature = "sepolia-taker-swap-v2-tests")] #[test] fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { - // sepolia test - thread::sleep(Duration::from_secs(220)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2101,7 +2104,6 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { trading_amount, }; wait_pending_transactions(Address::from_slice(taker_address.as_bytes())); - thread::sleep(Duration::from_secs(3)); let funding_tx_refund = block_on(taker_coin.refund_taker_funding_timelock(refund_args)).unwrap(); log!( "Taker refunded ERC20 funding after pre-approval lock time was exceeded, tx hash: {:02x}", @@ -2113,7 +2115,8 @@ fn send_and_refund_taker_funding_exceed_pre_approve_timelock_erc20() { #[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_timelock_eth() { - thread::sleep(Duration::from_secs(150)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2166,7 +2169,8 @@ fn send_maker_payment_and_refund_timelock_eth() { #[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_timelock_erc20() { - thread::sleep(Duration::from_secs(120)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2220,7 +2224,8 @@ fn send_maker_payment_and_refund_timelock_erc20() { #[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_secret_eth() { - thread::sleep(Duration::from_secs(90)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2270,7 +2275,8 @@ fn send_maker_payment_and_refund_secret_eth() { #[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_maker_payment_and_refund_secret_erc20() { - thread::sleep(Duration::from_secs(60)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); @@ -2321,6 +2327,8 @@ fn send_maker_payment_and_refund_secret_erc20() { #[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_and_spend_maker_payment_eth() { + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ETH, ð_sepolia_conf(), false); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ETH, ð_sepolia_conf(), false); @@ -2383,7 +2391,8 @@ fn send_and_spend_maker_payment_eth() { #[cfg(feature = "sepolia-maker-swap-v2-tests")] #[test] fn send_and_spend_maker_payment_erc20() { - thread::sleep(Duration::from_secs(30)); + let _guard = SEPOLIA_TESTS_LOCK.lock().unwrap(); + let erc20_conf = &sepolia_erc20_dev_conf(&sepolia_erc20_contract_checksum()); let taker_coin = get_or_create_sepolia_coin(&MM_CTX1, SEPOLIA_TAKER_PRIV, ERC20, erc20_conf, true); let maker_coin = get_or_create_sepolia_coin(&MM_CTX, SEPOLIA_MAKER_PRIV, ERC20, erc20_conf, true); From 638afd2766ad59271adecd5abac1a5f85461b6b2 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 24 Sep 2024 14:43:46 +0700 Subject: [PATCH 22/38] UtxoStandardCoin wait_for_maker_payment_spend --- mm2src/coins/utxo/utxo_standard.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 9a4f69ef4b..7d2030a921 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -666,11 +666,20 @@ impl MakerCoinSwapOpsV2 for UtxoStandardCoin { async fn wait_for_maker_payment_spend( &self, - _maker_payment: &Self::Tx, - _from_block: u64, - _wait_until: u64, + maker_payment: &Self::Tx, + from_block: u64, + wait_until: u64, ) -> MmResult { - todo!() + let res = utxo_common::wait_for_output_spend_impl( + self.as_ref(), + maker_payment, + utxo_common::DEFAULT_SWAP_VOUT, + from_block, + wait_until, + 10., + ) + .await?; + Ok(res) } } From be1eab0a3cba8cb8bc1e4aa916b7591a97ac63bb Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 25 Sep 2024 20:16:37 +0700 Subject: [PATCH 23/38] call crate BigDecimal method is_positive --- mm2src/coins/eth/eth_swap_v2/mod.rs | 7 ++----- mm2src/coins/eth/nft_swap_v2/mod.rs | 3 ++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index 1591452af4..9882decb6f 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -6,6 +6,7 @@ use ethereum_types::{Address, U256}; use futures::compat::Future01CompatExt; use mm2_err_handle::mm_error::MmError; use mm2_number::BigDecimal; +use num_traits::Signed; use web3::types::Transaction as Web3Tx; pub(crate) mod eth_maker_swap_v2; @@ -137,17 +138,13 @@ pub(crate) fn validate_from_to_and_status( Ok(()) } -/// function to check if BigDecimal is a positive value -#[inline(always)] -fn is_positive(amount: &BigDecimal) -> bool { amount > &BigDecimal::from(0) } - // TODO validate premium when add its support in swap_v2 fn validate_payment_args<'a>( taker_secret_hash: &'a [u8], maker_secret_hash: &'a [u8], trading_amount: &BigDecimal, ) -> Result<(), String> { - if !is_positive(trading_amount) { + if !trading_amount.is_positive() { return Err("trading_amount must be a positive value".to_string()); } if taker_secret_hash.len() != 32 { diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index d6eea6cb50..174c53dd4f 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -6,6 +6,7 @@ use ethkey::public_to_address; use futures::compat::Future01CompatExt; use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; use mm2_number::BigDecimal; +use num_traits::Signed; use web3::types::TransactionId; pub(crate) mod errors; @@ -580,7 +581,7 @@ fn htlc_params() -> &'static [ethabi::ParamType] { /// function to check if BigDecimal is a positive integer #[inline(always)] -fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } +fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount.is_positive() } fn validate_payment_args<'a>( taker_secret_hash: &'a [u8], From ab0f9617a5cacc5daa9a7ef5fb862d464ea7aac9 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 26 Sep 2024 12:19:31 +0700 Subject: [PATCH 24/38] fix clippy --- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 1 - 1 file changed, 1 deletion(-) 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 ed5316e0ac..f70c998d43 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -28,7 +28,6 @@ use coins::{CoinsContext, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, GenT use common::{block_on, block_on_f01, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; -use futures01::Future; #[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}; From b3ed7bacd700357a10c42418d43c4022986ecb29 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 26 Sep 2024 20:18:37 +0700 Subject: [PATCH 25/38] review: gas limit traits --- mm2src/coins/eth.rs | 80 +++++++++++++++++++ .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 64 ++++++--------- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 60 ++++++-------- mm2src/coins/eth/eth_swap_v2/mod.rs | 9 ++- mm2src/coins/eth/nft_swap_v2/mod.rs | 34 ++++---- 5 files changed, 152 insertions(+), 95 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 8107c90e52..9612efeec3 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -158,6 +158,7 @@ pub(crate) use eip1559_gas_fee::FeePerGasEstimated; use eip1559_gas_fee::{BlocknativeGasApiCaller, FeePerGasSimpleEstimator, GasApiConfig, GasApiProvider, InfuraGasApiCaller}; pub(crate) mod eth_swap_v2; +use eth_swap_v2::{EthPaymentType, PaymentMethod}; /// https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol /// Dev chain (195.201.137.5:8565) contract address: 0x83965C539899cC0F918552e5A26915de40ee8852 @@ -378,6 +379,85 @@ pub struct NftMakerGasLimitV2 { pub erc1155_maker_refund_secret: u64, } +pub trait NftGasLimit { + fn nft_gas_limit(&self, contract_type: &ContractType, method: PaymentMethod) -> u64; +} + +impl NftGasLimit for EthGasLimitV2 { + fn nft_gas_limit(&self, contract_type: &ContractType, method: PaymentMethod) -> u64 { + match contract_type { + ContractType::Erc1155 => match method { + PaymentMethod::Send => self.nft_maker.erc1155_payment, + PaymentMethod::Spend => self.nft_maker.erc1155_taker_spend, + PaymentMethod::RefundTimelock => self.nft_maker.erc1155_maker_refund_timelock, + PaymentMethod::RefundSecret => self.nft_maker.erc1155_maker_refund_secret, + }, + ContractType::Erc721 => match method { + PaymentMethod::Send => self.nft_maker.erc721_payment, + PaymentMethod::Spend => self.nft_maker.erc721_taker_spend, + PaymentMethod::RefundTimelock => self.nft_maker.erc721_maker_refund_timelock, + PaymentMethod::RefundSecret => self.nft_maker.erc721_maker_refund_secret, + }, + } + } +} + +pub trait GasLimit { + fn gas_limit( + &self, + coin_type: &EthCoinType, + payment_type: EthPaymentType, + method: PaymentMethod, + ) -> Result<(Address, u64), String>; +} + +impl GasLimit for EthGasLimitV2 { + fn gas_limit( + &self, + coin_type: &EthCoinType, + payment_type: EthPaymentType, + method: PaymentMethod, + ) -> Result<(Address, u64), String> { + match coin_type { + EthCoinType::Eth => { + let gas_limit = match payment_type { + EthPaymentType::MakerPayments => match method { + PaymentMethod::Send => self.maker.eth_payment, + PaymentMethod::Spend => self.maker.eth_taker_spend, + PaymentMethod::RefundTimelock => self.maker.eth_maker_refund_timelock, + PaymentMethod::RefundSecret => self.maker.eth_maker_refund_secret, + }, + EthPaymentType::TakerPayments => match method { + PaymentMethod::Send => self.taker.eth_payment, + PaymentMethod::Spend => self.taker.eth_maker_spend, + PaymentMethod::RefundTimelock => self.taker.eth_taker_refund_timelock, + PaymentMethod::RefundSecret => self.taker.eth_taker_refund_secret, + }, + }; + Ok((Address::default(), gas_limit)) + }, + EthCoinType::Erc20 { token_addr, .. } => { + let gas_limit = match payment_type { + EthPaymentType::MakerPayments => match method { + PaymentMethod::Send => self.maker.erc20_payment, + PaymentMethod::Spend => self.maker.erc20_taker_spend, + PaymentMethod::RefundTimelock => self.maker.erc20_maker_refund_timelock, + PaymentMethod::RefundSecret => self.maker.erc20_maker_refund_secret, + }, + EthPaymentType::TakerPayments => match method { + PaymentMethod::Send => self.taker.erc20_payment, + PaymentMethod::Spend => self.taker.erc20_maker_spend, + PaymentMethod::RefundTimelock => self.taker.erc20_taker_refund_timelock, + PaymentMethod::RefundSecret => self.taker.erc20_taker_refund_secret, + }, + }; + Ok((*token_addr, gas_limit)) + }, + EthCoinType::Nft { .. } => Err("NFT protocol is not supported for ETH and ERC20 Swaps".to_string()), + } + } +} + impl Default for MakerGasLimitV2 { fn default() -> Self { MakerGasLimitV2 { 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 0313d1d7fc..deb0e7224d 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 @@ -1,6 +1,7 @@ -use super::{validate_from_to_and_status, validate_payment_args, EthPaymentType, PrepareTxDataError, ZERO_VALUE}; +use super::{validate_from_to_and_status, validate_payment_args, EthPaymentType, PaymentMethod, PrepareTxDataError, + ZERO_VALUE}; use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; -use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, +use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, GasLimit, MakerPaymentStateV2, SignedEthTx, MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, TransactionErr, ValidateMakerPaymentArgs, @@ -181,18 +182,14 @@ impl EthCoin { &self, args: RefundMakerPaymentTimelockArgs<'_>, ) -> Result { - let (token_address, gas_limit) = match &self.coin_type { - EthCoinType::Eth => (Address::default(), self.gas_limit_v2.maker.eth_maker_refund_timelock), - EthCoinType::Erc20 { - platform: _, - token_addr, - } => (*token_addr, self.gas_limit_v2.maker.erc20_maker_refund_timelock), - EthCoinType::Nft { .. } => { - return Err(TransactionErr::ProtocolNotSupported(ERRL!( - "NFT protocol is not supported for ETH and ERC20 Swaps" - ))) - }, - }; + let (token_address, gas_limit) = self + .gas_limit_v2 + .gas_limit( + &self.coin_type, + EthPaymentType::MakerPayments, + PaymentMethod::RefundTimelock, + ) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let maker_swap_v2_contract = self .swap_v2_contracts @@ -239,18 +236,14 @@ impl EthCoin { &self, args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result { - let (token_address, gas_limit) = match &self.coin_type { - EthCoinType::Eth => (Address::default(), self.gas_limit_v2.maker.eth_maker_refund_secret), - EthCoinType::Erc20 { - platform: _, - token_addr, - } => (*token_addr, self.gas_limit_v2.maker.erc20_maker_refund_secret), - EthCoinType::Nft { .. } => { - return Err(TransactionErr::ProtocolNotSupported(ERRL!( - "NFT protocol is not supported for ETH and ERC20 Swaps" - ))) - }, - }; + let (token_address, gas_limit) = self + .gas_limit_v2 + .gas_limit( + &self.coin_type, + EthPaymentType::MakerPayments, + PaymentMethod::RefundSecret, + ) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let maker_swap_v2_contract = self .swap_v2_contracts @@ -288,18 +281,11 @@ impl EthCoin { &self, args: SpendMakerPaymentArgs<'_, Self>, ) -> Result { - let (token_address, gas_limit) = match &self.coin_type { - EthCoinType::Eth => (Address::default(), U256::from(self.gas_limit_v2.maker.eth_taker_spend)), - EthCoinType::Erc20 { - platform: _, - token_addr, - } => (*token_addr, U256::from(self.gas_limit_v2.maker.erc20_taker_spend)), - EthCoinType::Nft { .. } => { - return Err(TransactionErr::ProtocolNotSupported(ERRL!( - "NFT protocol is not supported for ETH and ERC20 Swaps" - ))) - }, - }; + let (token_address, gas_limit) = self + .gas_limit_v2 + .gas_limit(&self.coin_type, EthPaymentType::MakerPayments, PaymentMethod::Spend) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let maker_swap_v2_contract = self .swap_v2_contracts .as_ref() @@ -312,7 +298,7 @@ impl EthCoin { U256::from(ZERO_VALUE), Action::Call(maker_swap_v2_contract), data, - gas_limit, + U256::from(gas_limit), ) .compat() .await 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 56eb5dcf4e..f0cfdc8eea 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 @@ -1,6 +1,6 @@ use super::{check_decoded_length, validate_from_to_and_status, validate_payment_args, validate_payment_state, - EthPaymentType, PrepareTxDataError, ZERO_VALUE}; -use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, + EthPaymentType, PaymentMethod, PrepareTxDataError, ZERO_VALUE}; +use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, GasLimit, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, TransactionErr, ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; @@ -246,18 +246,14 @@ impl EthCoin { &self, args: RefundTakerPaymentArgs<'_>, ) -> Result { - let (token_address, gas_limit) = match &self.coin_type { - EthCoinType::Eth => (Address::default(), self.gas_limit_v2.taker.eth_taker_refund_timelock), - EthCoinType::Erc20 { - platform: _, - token_addr, - } => (*token_addr, self.gas_limit_v2.taker.erc20_taker_refund_timelock), - EthCoinType::Nft { .. } => { - return Err(TransactionErr::ProtocolNotSupported(ERRL!( - "NFT protocol is not supported for ETH and ERC20 Swaps" - ))) - }, - }; + let (token_address, gas_limit) = self + .gas_limit_v2 + .gas_limit( + &self.coin_type, + EthPaymentType::TakerPayments, + PaymentMethod::RefundTimelock, + ) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let taker_swap_v2_contract = self .swap_v2_contracts @@ -311,18 +307,14 @@ impl EthCoin { &self, args: RefundFundingSecretArgs<'_, Self>, ) -> Result { - let (token_address, gas_limit) = match &self.coin_type { - EthCoinType::Eth => (Address::default(), self.gas_limit_v2.taker.eth_taker_refund_secret), - EthCoinType::Erc20 { - platform: _, - token_addr, - } => (*token_addr, self.gas_limit_v2.taker.erc20_taker_refund_secret), - EthCoinType::Nft { .. } => { - return Err(TransactionErr::ProtocolNotSupported(ERRL!( - "NFT protocol is not supported for ETH and ERC20 Swaps" - ))) - }, - }; + let (token_address, gas_limit) = self + .gas_limit_v2 + .gas_limit( + &self.coin_type, + EthPaymentType::TakerPayments, + PaymentMethod::RefundSecret, + ) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let taker_swap_v2_contract = self .swap_v2_contracts @@ -396,15 +388,11 @@ impl EthCoin { gen_args: &GenTakerPaymentSpendArgs<'_, Self>, secret: &[u8], ) -> Result { - let gas_limit = match self.coin_type { - EthCoinType::Eth => U256::from(self.gas_limit_v2.taker.eth_maker_spend), - EthCoinType::Erc20 { .. } => U256::from(self.gas_limit_v2.taker.erc20_maker_spend), - EthCoinType::Nft { .. } => { - return Err(TransactionErr::ProtocolNotSupported(ERRL!( - "NFT protocol is not supported for ETH and ERC20 Swaps" - ))) - }, - }; + let (_, gas_limit) = self + .gas_limit_v2 + .gas_limit(&self.coin_type, EthPaymentType::TakerPayments, PaymentMethod::Spend) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let (taker_swap_v2_contract, approve_func, token_address) = self .taker_swap_v2_details(TAKER_PAYMENT_APPROVE, TAKER_PAYMENT_APPROVE) .await?; @@ -434,7 +422,7 @@ impl EthCoin { U256::from(ZERO_VALUE), Action::Call(taker_swap_v2_contract), data, - gas_limit, + U256::from(gas_limit), ) .compat() .await?; diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index 9882decb6f..8e099c236c 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -18,7 +18,7 @@ pub(crate) mod eth_taker_swap_v2; /// is provided as part of the input data rather than as an Ether value pub(crate) const ZERO_VALUE: u32 = 0; -pub(crate) enum EthPaymentType { +pub enum EthPaymentType { MakerPayments, TakerPayments, } @@ -32,6 +32,13 @@ impl EthPaymentType { } } +pub enum PaymentMethod { + Send, + Spend, + RefundTimelock, + RefundSecret, +} + #[derive(Debug, Display)] pub(crate) enum ValidatePaymentV2Err { UnexpectedPaymentState(String), diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 174c53dd4f..96d35b4ab6 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -14,9 +14,9 @@ use errors::{Erc721FunctionError, HtlcParamsError}; mod structs; use structs::{ExpectedHtlcParams, ValidationParams}; -use super::ContractType; -use crate::eth::eth_swap_v2::{validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentStatusErr, - PrepareTxDataError, ZERO_VALUE}; +use super::{ContractType, NftGasLimit}; +use crate::eth::eth_swap_v2::{validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentMethod, + PaymentStatusErr, PrepareTxDataError, ZERO_VALUE}; use crate::eth::{decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, ERC1155_CONTRACT, ERC721_CONTRACT, NFT_MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundNftMakerPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, @@ -38,10 +38,9 @@ impl EthCoin { let htlc_data = try_tx_s!(self.prepare_htlc_data(&args)); let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data(&args, htlc_data).await); - let gas_limit = match args.nft_swap_info.contract_type { - ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_payment, - ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_payment, - }; + let gas_limit = self + .gas_limit_v2 + .nft_gas_limit(args.nft_swap_info.contract_type, PaymentMethod::Send); self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(*args.nft_swap_info.token_address), @@ -178,10 +177,9 @@ impl EthCoin { .await ); let data = try_tx_s!(self.prepare_spend_nft_maker_v2_data(&args, decoded, htlc_params, state)); - let gas_limit = match args.contract_type { - ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_taker_spend, - ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_taker_spend, - }; + let gas_limit = self + .gas_limit_v2 + .nft_gas_limit(args.contract_type, PaymentMethod::Spend); self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(nft_maker_swap_v2_contract), @@ -228,10 +226,9 @@ impl EthCoin { ); let data = try_tx_s!(self.prepare_refund_nft_maker_payment_v2_timelock(&args, decoded, htlc_params, state)); - let gas_limit = match args.contract_type { - ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_maker_refund_timelock, - ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_maker_refund_timelock, - }; + let gas_limit = self + .gas_limit_v2 + .nft_gas_limit(args.contract_type, PaymentMethod::RefundTimelock); self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(nft_maker_swap_v2_contract), @@ -279,10 +276,9 @@ impl EthCoin { let data = try_tx_s!(self.prepare_refund_nft_maker_payment_v2_secret(&args, decoded, htlc_params, state)); - let gas_limit = match args.contract_type { - ContractType::Erc1155 => self.gas_limit_v2.nft_maker.erc1155_maker_refund_secret, - ContractType::Erc721 => self.gas_limit_v2.nft_maker.erc721_maker_refund_secret, - }; + let gas_limit = self + .gas_limit_v2 + .nft_gas_limit(args.contract_type, PaymentMethod::RefundSecret); self.sign_and_send_transaction( ZERO_VALUE.into(), Action::Call(nft_maker_swap_v2_contract), From 3dce044c91bef756b9b5b00964d80f6e77973008 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 7 Oct 2024 16:42:19 +0700 Subject: [PATCH 26/38] review: remove traits --- mm2src/coins/eth.rs | 52 +++++++------------ .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 2 +- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 2 +- mm2src/coins/eth/nft_swap_v2/mod.rs | 14 ++--- 4 files changed, 28 insertions(+), 42 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 9612efeec3..a203b8911e 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -379,39 +379,7 @@ pub struct NftMakerGasLimitV2 { pub erc1155_maker_refund_secret: u64, } -pub trait NftGasLimit { - fn nft_gas_limit(&self, contract_type: &ContractType, method: PaymentMethod) -> u64; -} - -impl NftGasLimit for EthGasLimitV2 { - fn nft_gas_limit(&self, contract_type: &ContractType, method: PaymentMethod) -> u64 { - match contract_type { - ContractType::Erc1155 => match method { - PaymentMethod::Send => self.nft_maker.erc1155_payment, - PaymentMethod::Spend => self.nft_maker.erc1155_taker_spend, - PaymentMethod::RefundTimelock => self.nft_maker.erc1155_maker_refund_timelock, - PaymentMethod::RefundSecret => self.nft_maker.erc1155_maker_refund_secret, - }, - ContractType::Erc721 => match method { - PaymentMethod::Send => self.nft_maker.erc721_payment, - PaymentMethod::Spend => self.nft_maker.erc721_taker_spend, - PaymentMethod::RefundTimelock => self.nft_maker.erc721_maker_refund_timelock, - PaymentMethod::RefundSecret => self.nft_maker.erc721_maker_refund_secret, - }, - } - } -} - -pub trait GasLimit { - fn gas_limit( - &self, - coin_type: &EthCoinType, - payment_type: EthPaymentType, - method: PaymentMethod, - ) -> Result<(Address, u64), String>; -} - -impl GasLimit for EthGasLimitV2 { +impl EthGasLimitV2 { fn gas_limit( &self, coin_type: &EthCoinType, @@ -456,6 +424,23 @@ impl GasLimit for EthGasLimitV2 { EthCoinType::Nft { .. } => Err("NFT protocol is not supported for ETH and ERC20 Swaps".to_string()), } } + + fn nft_gas_limit(&self, contract_type: &ContractType, method: PaymentMethod) -> u64 { + match contract_type { + ContractType::Erc1155 => match method { + PaymentMethod::Send => self.nft_maker.erc1155_payment, + PaymentMethod::Spend => self.nft_maker.erc1155_taker_spend, + PaymentMethod::RefundTimelock => self.nft_maker.erc1155_maker_refund_timelock, + PaymentMethod::RefundSecret => self.nft_maker.erc1155_maker_refund_secret, + }, + ContractType::Erc721 => match method { + PaymentMethod::Send => self.nft_maker.erc721_payment, + PaymentMethod::Spend => self.nft_maker.erc721_taker_spend, + PaymentMethod::RefundTimelock => self.nft_maker.erc721_maker_refund_timelock, + PaymentMethod::RefundSecret => self.nft_maker.erc721_maker_refund_secret, + }, + } + } } impl Default for MakerGasLimitV2 { @@ -906,6 +891,7 @@ pub struct EthCoinImpl { pub(crate) platform_fee_estimator_state: Arc, /// Config provided gas limits for swap and send transactions pub(crate) gas_limit: EthGasLimit, + /// Config provided gas limits v2 for swap v2 transactions pub(crate) gas_limit_v2: EthGasLimitV2, /// This spawner is used to spawn coin's related futures that should be aborted on coin deactivation /// and on [`MmArc::stop`]. 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 deb0e7224d..ac2042be68 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 @@ -1,7 +1,7 @@ use super::{validate_from_to_and_status, validate_payment_args, EthPaymentType, PaymentMethod, PrepareTxDataError, ZERO_VALUE}; use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; -use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, GasLimit, +use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, TransactionErr, ValidateMakerPaymentArgs, 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 f0cfdc8eea..997cce1eb5 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 @@ -1,6 +1,6 @@ use super::{check_decoded_length, validate_from_to_and_status, validate_payment_args, validate_payment_state, EthPaymentType, PaymentMethod, PrepareTxDataError, ZERO_VALUE}; -use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, GasLimit, +use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, TransactionErr, ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 96d35b4ab6..67dbeb111d 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -1,4 +1,3 @@ -use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use ethabi::{Contract, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, U256}; @@ -9,12 +8,8 @@ use mm2_number::BigDecimal; use num_traits::Signed; use web3::types::TransactionId; -pub(crate) mod errors; -use errors::{Erc721FunctionError, HtlcParamsError}; -mod structs; -use structs::{ExpectedHtlcParams, ValidationParams}; - -use super::{ContractType, NftGasLimit}; +use super::ContractType; +use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use crate::eth::eth_swap_v2::{validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentMethod, PaymentStatusErr, PrepareTxDataError, ZERO_VALUE}; use crate::eth::{decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, ERC1155_CONTRACT, @@ -22,6 +17,11 @@ use crate::eth::{decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2 use crate::{ParseCoinAssocTypes, RefundNftMakerPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, ValidateNftMakerPaymentArgs}; +pub(crate) mod errors; +use errors::{Erc721FunctionError, HtlcParamsError}; +mod structs; +use structs::{ExpectedHtlcParams, ValidationParams}; + impl EthCoin { pub(crate) async fn send_nft_maker_payment_v2_impl( &self, From db6b2e735ec93e05e47ff03b34eb60918120d229 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 1 Nov 2024 18:25:41 +0700 Subject: [PATCH 27/38] remove wait_for_maker_payment_spend --- mm2src/coins/eth.rs | 9 ---- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 51 +------------------ mm2src/coins/lp_coins.rs | 8 --- mm2src/coins/utxo/utxo_standard.rs | 18 ------- .../tests/docker_tests/eth_docker_tests.rs | 4 -- 5 files changed, 2 insertions(+), 88 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index b62a985f72..230401a4cd 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -7482,13 +7482,4 @@ impl MakerCoinSwapOpsV2 for EthCoin { async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result { self.spend_maker_payment_v2_impl(args).await } - - async fn wait_for_maker_payment_spend( - &self, - maker_payment: &Self::Tx, - _from_block: u64, - wait_until: u64, - ) -> MmResult { - self.wait_for_maker_payment_spend_impl(maker_payment, wait_until).await - } } 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 ac2042be68..992e053951 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 @@ -4,17 +4,14 @@ use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundMakerPaymentSecretArgs, RefundMakerPaymentTimelockArgs, SendMakerPaymentArgs, - SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, TransactionErr, ValidateMakerPaymentArgs, - WaitForPaymentSpendError}; -use common::executor::Timer; -use common::now_sec; + SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, TransactionErr, ValidateMakerPaymentArgs}; use ethabi::{Function, Token}; use ethcore_transaction::Action; use ethereum_types::{Address, Public, U256}; use ethkey::public_to_address; use futures::compat::Future01CompatExt; use mm2_err_handle::mm_error::MmError; -use mm2_err_handle::prelude::{MapToMmResult, MmResult}; +use mm2_err_handle::prelude::MapToMmResult; use std::convert::TryInto; use web3::types::TransactionId; @@ -304,50 +301,6 @@ impl EthCoin { .await } - pub(crate) async fn wait_for_maker_payment_spend_impl( - &self, - maker_payment: &SignedEthTx, - wait_until: u64, - ) -> MmResult { - let decoded = { - let func = match self.coin_type { - EthCoinType::Eth | EthCoinType::Erc20 { .. } => MAKER_SWAP_V2.function("spendMakerPayment")?, - EthCoinType::Nft { .. } => { - return MmError::err(WaitForPaymentSpendError::Internal( - "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), - )); - }, - }; - decode_contract_call(func, maker_payment.unsigned().data())? - }; - let maker_swap_v2_contract = self - .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) - .ok_or_else(|| { - WaitForPaymentSpendError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) - })?; - loop { - let maker_status = self - .payment_status_v2( - maker_swap_v2_contract, - decoded[0].clone(), // id from spendMakerPayment - &MAKER_SWAP_V2, - EthPaymentType::MakerPayments, - 2, - ) - .await?; - if maker_status == U256::from(MakerPaymentStateV2::TakerSpent as u8) { - return Ok(maker_payment.clone()); - } - let now = now_sec(); - if now > wait_until { - return MmError::err(WaitForPaymentSpendError::Timeout { wait_until, now }); - } - Timer::sleep(10.).await; - } - } - /// Prepares data for EtomicSwapMakerV2 contract [ethMakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L30) method async fn prepare_maker_eth_payment_data(&self, args: &MakerPaymentArgs) -> Result, PrepareTxDataError> { let function = MAKER_SWAP_V2.function(ETH_MAKER_PAYMENT)?; diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index a1617aa912..60ab37e5a0 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1746,14 +1746,6 @@ pub trait MakerCoinSwapOpsV2: ParseCoinAssocTypes + CommonSwapOpsV2 + Send + Syn /// Spend maker payment transaction async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result; - - /// Wait until maker payment spend is found on-chain - async fn wait_for_maker_payment_spend( - &self, - maker_payment: &Self::Tx, - from_block: u64, - wait_until: u64, - ) -> MmResult; } #[async_trait] diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index dd6d63f256..ee03487faa 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -685,24 +685,6 @@ impl MakerCoinSwapOpsV2 for UtxoStandardCoin { async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result { utxo_common::spend_maker_payment_v2(self, args).await } - - async fn wait_for_maker_payment_spend( - &self, - maker_payment: &Self::Tx, - from_block: u64, - wait_until: u64, - ) -> MmResult { - let res = utxo_common::wait_for_output_spend_impl( - self.as_ref(), - maker_payment, - utxo_common::DEFAULT_SWAP_VOUT, - from_block, - wait_until, - 10., - ) - .await?; - Ok(res) - } } #[async_trait] 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 4368caa3df..8b04e3f50c 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -2383,8 +2383,6 @@ fn send_and_spend_maker_payment_eth() { let spend_tx = block_on(taker_coin.spend_maker_payment_v2(spend_args)).unwrap(); log!("Taker spent maker ETH payment, tx hash: {:02x}", spend_tx.tx_hash()); wait_for_confirmations(&taker_coin, &spend_tx, 100); - - block_on(maker_coin.wait_for_maker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } #[cfg(feature = "sepolia-maker-swap-v2-tests")] @@ -2448,6 +2446,4 @@ fn send_and_spend_maker_payment_erc20() { let spend_tx = block_on(taker_coin.spend_maker_payment_v2(spend_args)).unwrap(); log!("Taker spent maker ERC20 payment, tx hash: {:02x}", spend_tx.tx_hash()); wait_for_confirmations(&taker_coin, &spend_tx, 100); - - block_on(maker_coin.wait_for_maker_payment_spend(&spend_tx, 0u64, payment_time_lock)).unwrap(); } From da12b97d28c6992af007315271c12ce37c56050d Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 1 Nov 2024 19:11:47 +0700 Subject: [PATCH 28/38] increase v2 ERC20_PAYMENT consts to 150_000 --- mm2src/coins/eth.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 230401a4cd..f2d9411acb 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -257,7 +257,7 @@ pub mod gas_limit_v2 { /// Gas limits for maker operations in EtomicSwapMakerV2 contract pub mod maker { pub const ETH_PAYMENT: u64 = 65_000; - pub const ERC20_PAYMENT: u64 = 115_000; + pub const ERC20_PAYMENT: u64 = 150_000; pub const ETH_TAKER_SPEND: u64 = 65_000; pub const ERC20_TAKER_SPEND: u64 = 65_000; pub const ETH_MAKER_REFUND_TIMELOCK: u64 = 65_000; @@ -269,7 +269,7 @@ pub mod gas_limit_v2 { /// Gas limits for taker operations in EtomicSwapTakerV2 contract pub mod taker { pub const ETH_PAYMENT: u64 = 65_000; - pub const ERC20_PAYMENT: u64 = 115_000; + pub const ERC20_PAYMENT: u64 = 150_000; pub const ETH_MAKER_SPEND: u64 = 100_000; pub const ERC20_MAKER_SPEND: u64 = 115_000; pub const ETH_TAKER_REFUND_TIMELOCK: u64 = 65_000; From 2b81855af3a52121d924eade11c1abf423e074ee Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 1 Nov 2024 20:33:42 +0700 Subject: [PATCH 29/38] review: consts for TAKER/MAKER state indexes --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 11 +++++++++- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 20 ++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) 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 992e053951..b8aa3aaf71 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,6 +18,15 @@ use web3::types::TransactionId; const ETH_MAKER_PAYMENT: &str = "ethMakerPayment"; const ERC20_MAKER_PAYMENT: &str = "erc20MakerPayment"; +/// state index for `MakerPayment` structure from `EtomicSwapMakerV2.sol` +/// +/// struct MakerPayment { +/// bytes20 paymentHash; +/// uint32 paymentLockTime; +/// MakerPaymentState state; +/// } +const MAKER_PAYMENT_STATE_INDX: usize = 2; + struct MakerPaymentArgs { taker_address: Address, taker_secret_hash: [u8; 32], @@ -127,7 +136,7 @@ impl EthCoin { Token::FixedBytes(swap_id.clone()), &MAKER_SWAP_V2, EthPaymentType::MakerPayments, - 2, + MAKER_PAYMENT_STATE_INDX, ) .await?; 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 997cce1eb5..621d9df743 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 @@ -21,6 +21,16 @@ const ETH_TAKER_PAYMENT: &str = "ethTakerPayment"; const ERC20_TAKER_PAYMENT: &str = "erc20TakerPayment"; const TAKER_PAYMENT_APPROVE: &str = "takerPaymentApprove"; +/// state index for `TakerPayment` structure from `EtomicSwapTakerV2.sol` +/// +/// struct TakerPayment { +/// bytes20 paymentHash; +/// uint32 preApproveLockTime; +/// uint32 paymentLockTime; +/// TakerPaymentState state; +/// } +const TAKER_PAYMENT_STATE_INDX: usize = 3; + struct TakerFundingArgs { dex_fee: U256, payment_amount: U256, @@ -147,7 +157,7 @@ impl EthCoin { Token::FixedBytes(swap_id.clone()), &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - 3, + TAKER_PAYMENT_STATE_INDX, ) .await?; @@ -220,7 +230,7 @@ impl EthCoin { decoded[0].clone(), &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - 3, + TAKER_PAYMENT_STATE_INDX, ) .await ); @@ -371,7 +381,7 @@ impl EthCoin { decoded[0].clone(), // id from takerPaymentApprove &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - 3, + TAKER_PAYMENT_STATE_INDX, ) .await .map_err(|e| SearchForFundingSpendErr::Internal(ERRL!("{}", e)))?; @@ -403,7 +413,7 @@ impl EthCoin { decoded[0].clone(), &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - 3, + TAKER_PAYMENT_STATE_INDX, ) .await ); @@ -446,7 +456,7 @@ impl EthCoin { decoded[0].clone(), // id from spendTakerPayment &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - 3, + TAKER_PAYMENT_STATE_INDX, ) .await?; if taker_status == U256::from(TakerPaymentStateV2::MakerSpent as u8) { From 72ed3060ace61d9a14eca6fc5cedeb957ad0be54 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 1 Nov 2024 21:01:17 +0700 Subject: [PATCH 30/38] review: create separate Refund Args structures for Timelock and Secret functions --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 22 +++++++++++------- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 23 ++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) 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 b8aa3aaf71..164db7b8a4 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 @@ -43,16 +43,24 @@ struct MakerValidationArgs<'a> { payment_time_lock: u64, } -struct MakerRefundArgs { +struct MakerRefundTimelockArgs { payment_amount: U256, taker_address: Address, - taker_secret: [u8; 32], taker_secret_hash: [u8; 32], maker_secret_hash: [u8; 32], payment_time_lock: u64, token_address: Address, } +struct MakerRefundSecretArgs { + payment_amount: U256, + taker_address: Address, + taker_secret: [u8; 32], + maker_secret_hash: [u8; 32], + payment_time_lock: u64, + token_address: Address, +} + impl EthCoin { pub(crate) async fn send_maker_payment_v2_impl( &self, @@ -216,10 +224,9 @@ impl EthCoin { }; let args = { let taker_address = public_to_address(&Public::from_slice(args.taker_pub)); - MakerRefundArgs { + MakerRefundTimelockArgs { payment_amount, taker_address, - taker_secret: [0u8; 32], taker_secret_hash: try_tx_s!(taker_secret_hash.try_into()), maker_secret_hash: try_tx_s!(maker_secret_hash.try_into()), payment_time_lock: args.time_lock, @@ -261,11 +268,10 @@ impl EthCoin { let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); let args = { let taker_address = public_to_address(args.taker_pub); - MakerRefundArgs { + MakerRefundSecretArgs { payment_amount, taker_address, taker_secret, - taker_secret_hash: [0u8; 32], maker_secret_hash, payment_time_lock: args.time_lock, token_address, @@ -348,7 +354,7 @@ impl EthCoin { /// Prepares data for EtomicSwapMakerV2 contract [refundMakerPaymentTimelock](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L144) method async fn prepare_refund_maker_payment_timelock_data( &self, - args: MakerRefundArgs, + args: MakerRefundTimelockArgs, ) -> Result, PrepareTxDataError> { let function = MAKER_SWAP_V2.function("refundMakerPaymentTimelock")?; let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); @@ -366,7 +372,7 @@ impl EthCoin { /// Prepares data for EtomicSwapMakerV2 contract [refundMakerPaymentSecret](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapMakerV2.sol#L190) method async fn prepare_refund_maker_payment_secret_data( &self, - args: MakerRefundArgs, + args: MakerRefundSecretArgs, ) -> Result, PrepareTxDataError> { let function = MAKER_SWAP_V2.function("refundMakerPaymentSecret")?; let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); 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 621d9df743..52c1a2592a 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 @@ -41,17 +41,26 @@ struct TakerFundingArgs { payment_time_lock: u64, } -struct TakerRefundArgs { +struct TakerRefundTimelockArgs { dex_fee: U256, payment_amount: U256, maker_address: Address, - taker_secret: [u8; 32], taker_secret_hash: [u8; 32], maker_secret_hash: [u8; 32], payment_time_lock: u64, token_address: Address, } +struct TakerRefundSecretArgs { + dex_fee: U256, + payment_amount: U256, + maker_address: Address, + taker_secret: [u8; 32], + maker_secret_hash: [u8; 32], + payment_time_lock: u64, + token_address: Address, +} + struct TakerValidationArgs<'a> { swap_id: Vec, amount: U256, @@ -291,11 +300,10 @@ impl EthCoin { }, }; - let args = TakerRefundArgs { + let args = TakerRefundTimelockArgs { dex_fee, payment_amount, maker_address, - taker_secret: [0u8; 32], taker_secret_hash: try_tx_s!(taker_secret_hash.try_into()), maker_secret_hash: try_tx_s!(maker_secret_hash.try_into()), payment_time_lock: args.time_lock, @@ -343,12 +351,11 @@ impl EthCoin { )); let maker_address = public_to_address(args.maker_pubkey); - let refund_args = TakerRefundArgs { + let refund_args = TakerRefundSecretArgs { dex_fee, payment_amount, maker_address, taker_secret, - taker_secret_hash: [0u8; 32], maker_secret_hash, payment_time_lock: args.payment_time_lock, token_address, @@ -511,7 +518,7 @@ impl EthCoin { /// Prepares data for EtomicSwapTakerV2 contract [refundTakerPaymentTimelock](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L208) method async fn prepare_taker_refund_payment_timelock_data( &self, - args: TakerRefundArgs, + args: TakerRefundTimelockArgs, ) -> Result, PrepareTxDataError> { let function = TAKER_SWAP_V2.function("refundTakerPaymentTimelock")?; let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); @@ -530,7 +537,7 @@ impl EthCoin { /// Prepares data for EtomicSwapTakerV2 contract [refundTakerPaymentSecret](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L267) method async fn prepare_taker_refund_payment_secret_data( &self, - args: &TakerRefundArgs, + args: &TakerRefundSecretArgs, ) -> Result, PrepareTxDataError> { let function = TAKER_SWAP_V2.function("refundTakerPaymentSecret")?; let id = self.etomic_swap_id_v2(args.payment_time_lock, &args.maker_secret_hash); From a9a5c47551c39b37fc447a9feb6971c170f0d549 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 3 Nov 2024 15:06:29 +0700 Subject: [PATCH 31/38] review: remove unreachable --- mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs | 6 +++++- mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) 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 164db7b8a4..6f48f1d512 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 @@ -187,7 +187,11 @@ impl EthCoin { let decoded = decode_contract_call(function, &tx_from_rpc.input.0)?; validate_erc20_maker_payment_data(&decoded, &validation_args, function, token_addr)?; }, - EthCoinType::Nft { .. } => unreachable!(), + EthCoinType::Nft { .. } => { + return MmError::err(ValidatePaymentError::ProtocolNotSupported( + "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), + )); + }, } 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 52c1a2592a..0ba8ebbafa 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 @@ -210,7 +210,11 @@ impl EthCoin { let decoded = decode_contract_call(function, &tx_from_rpc.input.0)?; validate_erc20_taker_payment_data(&decoded, &validation_args, function, token_addr)?; }, - EthCoinType::Nft { .. } => unreachable!(), + EthCoinType::Nft { .. } => { + return MmError::err(ValidateSwapV2TxError::ProtocolNotSupported( + "NFT protocol is not supported for ETH and ERC20 Swaps".to_string(), + )); + }, } Ok(()) } From 1ccfc7748322c4be876c02f59580616b72a4812e Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 3 Nov 2024 16:12:45 +0700 Subject: [PATCH 32/38] review: split token_address and gas_limit funcs logic --- mm2src/coins/eth.rs | 8 ++++---- mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs | 15 ++++++++++++--- mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs | 12 +++++++++--- mm2src/coins/eth/eth_swap_v2/mod.rs | 10 +++++++++- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index f2d9411acb..010d8d4be7 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -385,7 +385,7 @@ impl EthGasLimitV2 { coin_type: &EthCoinType, payment_type: EthPaymentType, method: PaymentMethod, - ) -> Result<(Address, u64), String> { + ) -> Result { match coin_type { EthCoinType::Eth => { let gas_limit = match payment_type { @@ -402,9 +402,9 @@ impl EthGasLimitV2 { PaymentMethod::RefundSecret => self.taker.eth_taker_refund_secret, }, }; - Ok((Address::default(), gas_limit)) + Ok(gas_limit) }, - EthCoinType::Erc20 { token_addr, .. } => { + EthCoinType::Erc20 { .. } => { let gas_limit = match payment_type { EthPaymentType::MakerPayments => match method { PaymentMethod::Send => self.maker.erc20_payment, @@ -419,7 +419,7 @@ impl EthGasLimitV2 { PaymentMethod::RefundSecret => self.taker.erc20_taker_refund_secret, }, }; - Ok((*token_addr, gas_limit)) + Ok(gas_limit) }, EthCoinType::Nft { .. } => Err("NFT protocol is not supported for ETH and ERC20 Swaps".to_string()), } 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 6f48f1d512..f2212e49a5 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 @@ -200,7 +200,10 @@ impl EthCoin { &self, args: RefundMakerPaymentTimelockArgs<'_>, ) -> Result { - let (token_address, gas_limit) = self + let token_address = self + .get_token_address() + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let gas_limit = self .gas_limit_v2 .gas_limit( &self.coin_type, @@ -253,7 +256,10 @@ impl EthCoin { &self, args: RefundMakerPaymentSecretArgs<'_, Self>, ) -> Result { - let (token_address, gas_limit) = self + let token_address = self + .get_token_address() + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let gas_limit = self .gas_limit_v2 .gas_limit( &self.coin_type, @@ -297,7 +303,10 @@ impl EthCoin { &self, args: SpendMakerPaymentArgs<'_, Self>, ) -> Result { - let (token_address, gas_limit) = self + let token_address = self + .get_token_address() + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let gas_limit = self .gas_limit_v2 .gas_limit(&self.coin_type, EthPaymentType::MakerPayments, PaymentMethod::Spend) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; 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 0ba8ebbafa..f9d6b99d70 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 @@ -269,7 +269,10 @@ impl EthCoin { &self, args: RefundTakerPaymentArgs<'_>, ) -> Result { - let (token_address, gas_limit) = self + let token_address = self + .get_token_address() + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let gas_limit = self .gas_limit_v2 .gas_limit( &self.coin_type, @@ -329,7 +332,10 @@ impl EthCoin { &self, args: RefundFundingSecretArgs<'_, Self>, ) -> Result { - let (token_address, gas_limit) = self + let token_address = self + .get_token_address() + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let gas_limit = self .gas_limit_v2 .gas_limit( &self.coin_type, @@ -409,7 +415,7 @@ impl EthCoin { gen_args: &GenTakerPaymentSpendArgs<'_, Self>, secret: &[u8], ) -> Result { - let (_, gas_limit) = self + let gas_limit = self .gas_limit_v2 .gas_limit(&self.coin_type, EthPaymentType::TakerPayments, PaymentMethod::Spend) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index 8e099c236c..ff31330ce3 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -1,4 +1,4 @@ -use crate::eth::{EthCoin, ParseCoinAssocTypes, Transaction, TransactionErr}; +use crate::eth::{EthCoin, EthCoinType, ParseCoinAssocTypes, Transaction, TransactionErr}; use enum_derives::EnumFromStringify; use ethabi::{Contract, Token}; use ethcore_transaction::SignedTransaction as SignedEthTx; @@ -100,6 +100,14 @@ impl EthCoin { ))), } } + + pub(super) fn get_token_address(&self) -> Result { + match &self.coin_type { + EthCoinType::Eth => Ok(Address::default()), + EthCoinType::Erc20 { token_addr, .. } => Ok(*token_addr), + EthCoinType::Nft { .. } => Err("NFT protocol is not supported for ETH and ERC20 Swaps".to_string()), + } + } } pub(crate) fn validate_payment_state( From 6e42e34714b46a67bd241dbbccf7076f5a60c834 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 3 Nov 2024 17:15:48 +0700 Subject: [PATCH 33/38] review: adjust gas limit consts --- mm2src/coins/eth.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 010d8d4be7..f27a83b333 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -258,12 +258,12 @@ pub mod gas_limit_v2 { pub mod maker { pub const ETH_PAYMENT: u64 = 65_000; pub const ERC20_PAYMENT: u64 = 150_000; - pub const ETH_TAKER_SPEND: u64 = 65_000; - pub const ERC20_TAKER_SPEND: u64 = 65_000; - pub const ETH_MAKER_REFUND_TIMELOCK: u64 = 65_000; - pub const ERC20_MAKER_REFUND_TIMELOCK: u64 = 65_000; - pub const ETH_MAKER_REFUND_SECRET: u64 = 65_000; - pub const ERC20_MAKER_REFUND_SECRET: u64 = 65_000; + pub const ETH_TAKER_SPEND: u64 = 100_000; + pub const ERC20_TAKER_SPEND: u64 = 150_000; + pub const ETH_MAKER_REFUND_TIMELOCK: u64 = 90_000; + pub const ERC20_MAKER_REFUND_TIMELOCK: u64 = 100_000; + pub const ETH_MAKER_REFUND_SECRET: u64 = 90_000; + pub const ERC20_MAKER_REFUND_SECRET: u64 = 100_000; } /// Gas limits for taker operations in EtomicSwapTakerV2 contract @@ -272,10 +272,10 @@ pub mod gas_limit_v2 { pub const ERC20_PAYMENT: u64 = 150_000; pub const ETH_MAKER_SPEND: u64 = 100_000; pub const ERC20_MAKER_SPEND: u64 = 115_000; - pub const ETH_TAKER_REFUND_TIMELOCK: u64 = 65_000; - pub const ERC20_TAKER_REFUND_TIMELOCK: u64 = 70_000; - pub const ETH_TAKER_REFUND_SECRET: u64 = 65_000; - pub const ERC20_TAKER_REFUND_SECRET: u64 = 70_000; + pub const ETH_TAKER_REFUND_TIMELOCK: u64 = 90_000; + pub const ERC20_TAKER_REFUND_TIMELOCK: u64 = 100_000; + pub const ETH_TAKER_REFUND_SECRET: u64 = 90_000; + pub const ERC20_TAKER_REFUND_SECRET: u64 = 100_000; pub const APPROVE_PAYMENT: u64 = 50_000; } From ce15cd86dd16a3c4ac5909f36003d4100e482143 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 4 Nov 2024 19:41:43 +0700 Subject: [PATCH 34/38] review: prioritize errors --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 32 ++++---- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 78 ++++++++++--------- 2 files changed, 57 insertions(+), 53 deletions(-) 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 f2212e49a5..7c85d6dba8 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 @@ -203,6 +203,11 @@ impl EthCoin { let token_address = self .get_token_address() .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; let gas_limit = self .gas_limit_v2 .gas_limit( @@ -212,12 +217,6 @@ impl EthCoin { ) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let maker_swap_v2_contract = self - .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; - let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); let (maker_secret_hash, taker_secret_hash) = match args.tx_type_with_secret_hash { SwapTxTypeWithSecretHash::MakerPaymentV2 { maker_secret_hash, @@ -229,6 +228,8 @@ impl EthCoin { ))) }, }; + let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); + let args = { let taker_address = public_to_address(&Public::from_slice(args.taker_pub)); MakerRefundTimelockArgs { @@ -259,6 +260,11 @@ impl EthCoin { let token_address = self .get_token_address() .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let maker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.maker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; let gas_limit = self .gas_limit_v2 .gas_limit( @@ -268,11 +274,6 @@ impl EthCoin { ) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let maker_swap_v2_contract = self - .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; let taker_secret = try_tx_s!(args.taker_secret.try_into()); let maker_secret_hash = try_tx_s!(args.maker_secret_hash.try_into()); let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); @@ -306,16 +307,15 @@ impl EthCoin { let token_address = self .get_token_address() .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let gas_limit = self - .gas_limit_v2 - .gas_limit(&self.coin_type, EthPaymentType::MakerPayments, PaymentMethod::Spend) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let maker_swap_v2_contract = self .swap_v2_contracts .as_ref() .map(|contracts| contracts.maker_swap_v2_contract) .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + let gas_limit = self + .gas_limit_v2 + .gas_limit(&self.coin_type, EthPaymentType::MakerPayments, PaymentMethod::Spend) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let data = try_tx_s!(self.prepare_spend_maker_payment_data(args, token_address).await); 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 f9d6b99d70..6b434f7fd3 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 @@ -272,6 +272,11 @@ impl EthCoin { let token_address = self .get_token_address() .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let taker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.taker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; let gas_limit = self .gas_limit_v2 .gas_limit( @@ -281,20 +286,6 @@ impl EthCoin { ) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let taker_swap_v2_contract = self - .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.taker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; - let dex_fee = try_tx_s!(wei_from_big_decimal( - &args.dex_fee.fee_amount().to_decimal(), - self.decimals - )); - let payment_amount = try_tx_s!(wei_from_big_decimal( - &(args.trading_amount + args.premium_amount), - self.decimals - )); - let maker_address = public_to_address(&Public::from_slice(args.maker_pub)); let (maker_secret_hash, taker_secret_hash) = match args.tx_type_with_secret_hash { SwapTxTypeWithSecretHash::TakerPaymentV2 { maker_secret_hash, @@ -306,15 +297,26 @@ impl EthCoin { ))) }, }; + let dex_fee = try_tx_s!(wei_from_big_decimal( + &args.dex_fee.fee_amount().to_decimal(), + self.decimals + )); + let payment_amount = try_tx_s!(wei_from_big_decimal( + &(args.trading_amount + args.premium_amount), + self.decimals + )); - let args = TakerRefundTimelockArgs { - dex_fee, - payment_amount, - maker_address, - taker_secret_hash: try_tx_s!(taker_secret_hash.try_into()), - maker_secret_hash: try_tx_s!(maker_secret_hash.try_into()), - payment_time_lock: args.time_lock, - token_address, + let args = { + let maker_address = public_to_address(&Public::from_slice(args.maker_pub)); + TakerRefundTimelockArgs { + dex_fee, + payment_amount, + maker_address, + taker_secret_hash: try_tx_s!(taker_secret_hash.try_into()), + maker_secret_hash: try_tx_s!(maker_secret_hash.try_into()), + payment_time_lock: args.time_lock, + token_address, + } }; let data = try_tx_s!(self.prepare_taker_refund_payment_timelock_data(args).await); @@ -335,6 +337,11 @@ impl EthCoin { let token_address = self .get_token_address() .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let taker_swap_v2_contract = self + .swap_v2_contracts + .as_ref() + .map(|contracts| contracts.taker_swap_v2_contract) + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; let gas_limit = self .gas_limit_v2 .gas_limit( @@ -344,11 +351,6 @@ impl EthCoin { ) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let taker_swap_v2_contract = self - .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.taker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; let taker_secret = try_tx_s!(args.taker_secret.try_into()); let maker_secret_hash = try_tx_s!(args.maker_secret_hash.try_into()); let dex_fee = try_tx_s!(wei_from_big_decimal( @@ -359,16 +361,18 @@ impl EthCoin { &(args.trading_amount + args.premium_amount), self.decimals )); - let maker_address = public_to_address(args.maker_pubkey); - - let refund_args = TakerRefundSecretArgs { - dex_fee, - payment_amount, - maker_address, - taker_secret, - maker_secret_hash, - payment_time_lock: args.payment_time_lock, - token_address, + + let refund_args = { + let maker_address = public_to_address(args.maker_pubkey); + TakerRefundSecretArgs { + dex_fee, + payment_amount, + maker_address, + taker_secret, + maker_secret_hash, + payment_time_lock: args.payment_time_lock, + token_address, + } }; let data = try_tx_s!(self.prepare_taker_refund_payment_secret_data(&refund_args).await); From 57e75ed9354341cff841c4391871b75899f420b8 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 4 Nov 2024 19:59:25 +0700 Subject: [PATCH 35/38] review: remove unnecessary as_ref, map functions --- .../eth/eth_swap_v2/eth_maker_swap_v2.rs | 25 ++++++++----------- .../eth/eth_swap_v2/eth_taker_swap_v2.rs | 20 ++++++--------- mm2src/coins/eth/nft_swap_v2/mod.rs | 25 ++++++++----------- 3 files changed, 28 insertions(+), 42 deletions(-) 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 7c85d6dba8..2e1c9bec49 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 @@ -68,9 +68,8 @@ impl EthCoin { ) -> Result { let maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))? + .maker_swap_v2_contract; let payment_amount = try_tx_s!(wei_from_big_decimal(&args.amount, self.decimals)); let payment_args = { let taker_address = public_to_address(args.taker_pub); @@ -129,11 +128,10 @@ impl EthCoin { } let maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) .ok_or_else(|| { ValidatePaymentError::InternalError("Expected swap_v2_contracts to be Some, but found None".to_string()) - })?; + })? + .maker_swap_v2_contract; validate_payment_args(args.taker_secret_hash, args.maker_secret_hash, &args.amount) .map_to_mm(ValidatePaymentError::InternalError)?; let maker_address = public_to_address(args.maker_pub); @@ -205,9 +203,8 @@ impl EthCoin { .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))? + .maker_swap_v2_contract; let gas_limit = self .gas_limit_v2 .gas_limit( @@ -262,9 +259,8 @@ impl EthCoin { .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))? + .maker_swap_v2_contract; let gas_limit = self .gas_limit_v2 .gas_limit( @@ -309,9 +305,8 @@ impl EthCoin { .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.maker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))? + .maker_swap_v2_contract; let gas_limit = self .gas_limit_v2 .gas_limit(&self.coin_type, EthPaymentType::MakerPayments, PaymentMethod::Spend) 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 6b434f7fd3..c4deb86b21 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 @@ -81,9 +81,8 @@ impl EthCoin { ) -> Result { let taker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.taker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))? + .taker_swap_v2_contract; // TODO add burnFee support let dex_fee = try_tx_s!(wei_from_big_decimal(&args.dex_fee.fee_amount().into(), self.decimals)); @@ -151,11 +150,10 @@ impl EthCoin { } let taker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.taker_swap_v2_contract) .ok_or_else(|| { ValidateSwapV2TxError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) - })?; + })? + .taker_swap_v2_contract; validate_payment_args(args.taker_secret_hash, args.maker_secret_hash, &args.trading_amount) .map_err(ValidateSwapV2TxError::Internal)?; let taker_address = public_to_address(args.taker_pub); @@ -274,9 +272,8 @@ impl EthCoin { .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let taker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.taker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))? + .taker_swap_v2_contract; let gas_limit = self .gas_limit_v2 .gas_limit( @@ -339,9 +336,8 @@ impl EthCoin { .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let taker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.taker_swap_v2_contract) - .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))?; + .ok_or_else(|| TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")))? + .taker_swap_v2_contract; let gas_limit = self .gas_limit_v2 .gas_limit( diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 67dbeb111d..f4c909bd32 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -64,13 +64,12 @@ impl EthCoin { EthCoinType::Nft { .. } => { let nft_maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.nft_maker_swap_v2_contract) .ok_or_else(|| { ValidatePaymentError::InternalError( "Expected swap_v2_contracts to be Some, but found None".to_string(), ) - })?; + })? + .nft_maker_swap_v2_contract; let contract_type = args.nft_swap_info.contract_type; validate_payment_args( args.taker_secret_hash, @@ -152,11 +151,10 @@ impl EthCoin { EthCoinType::Nft { .. } => { let nft_maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.nft_maker_swap_v2_contract) .ok_or_else(|| { TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")) - })?; + })? + .nft_maker_swap_v2_contract; if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } @@ -203,11 +201,10 @@ impl EthCoin { EthCoinType::Nft { .. } => { let nft_maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.nft_maker_swap_v2_contract) .ok_or_else(|| { TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")) - })?; + })? + .nft_maker_swap_v2_contract; let (decoded, bytes_index) = try_tx_s!(get_decoded_tx_data_and_bytes_index( args.contract_type, args.maker_payment_tx.unsigned().data() @@ -252,11 +249,10 @@ impl EthCoin { EthCoinType::Nft { .. } => { let nft_maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.nft_maker_swap_v2_contract) .ok_or_else(|| { TransactionErr::Plain(ERRL!("Expected swap_v2_contracts to be Some, but found None")) - })?; + })? + .nft_maker_swap_v2_contract; let (decoded, bytes_index) = try_tx_s!(get_decoded_tx_data_and_bytes_index( args.contract_type, args.maker_payment_tx.unsigned().data() @@ -301,11 +297,10 @@ impl EthCoin { ) -> Result, PrepareTxDataError> { let nft_maker_swap_v2_contract = self .swap_v2_contracts - .as_ref() - .map(|contracts| contracts.nft_maker_swap_v2_contract) .ok_or_else(|| { PrepareTxDataError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) - })?; + })? + .nft_maker_swap_v2_contract; match args.nft_swap_info.contract_type { ContractType::Erc1155 => { let function = ERC1155_CONTRACT.function("safeTransferFrom")?; From 1e6ea8ee62775debaac27cf81772e3aa4625c106 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 4 Nov 2024 20:27:57 +0700 Subject: [PATCH 36/38] review: use ref to a fixed-size array in Validation Args --- mm2src/coins/coin_errors.rs | 5 +++-- mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs | 8 ++++---- mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs | 8 ++++---- mm2src/coins/lp_coins.rs | 3 ++- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 90e9fe413b..6075317bfc 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -6,7 +6,7 @@ use enum_derives::EnumFromStringify; use futures01::Future; use mm2_err_handle::prelude::MmError; use spv_validation::helpers_validation::SPVError; -use std::num::TryFromIntError; +use std::{array::TryFromSliceError, num::TryFromIntError}; /// Helper type used as result for swap payment validation function(s) pub type ValidatePaymentFut = Box> + Send>; @@ -25,7 +25,8 @@ pub enum ValidatePaymentError { "UnexpectedDerivationMethod", "keys::Error", "PrepareTxDataError", - "ethabi::Error" + "ethabi::Error", + "TryFromSliceError" )] InternalError(String), /// Problem with deserializing the transaction, or one of the transaction parts is invalid. 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 2e1c9bec49..6a52fa3fa4 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 @@ -38,8 +38,8 @@ struct MakerValidationArgs<'a> { swap_id: Vec, amount: U256, taker: Address, - taker_secret_hash: &'a [u8], - maker_secret_hash: &'a [u8], + taker_secret_hash: &'a [u8; 32], + maker_secret_hash: &'a [u8; 32], payment_time_lock: u64, } @@ -169,8 +169,8 @@ impl EthCoin { swap_id, amount, taker: self.my_addr().await, - taker_secret_hash: args.taker_secret_hash, - maker_secret_hash: args.maker_secret_hash, + taker_secret_hash: args.taker_secret_hash.try_into()?, + maker_secret_hash: args.maker_secret_hash.try_into()?, payment_time_lock: args.time_lock, } }; 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 c4deb86b21..fe07ab9953 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 @@ -66,8 +66,8 @@ struct TakerValidationArgs<'a> { amount: U256, dex_fee: U256, receiver: Address, - taker_secret_hash: &'a [u8], - maker_secret_hash: &'a [u8], + taker_secret_hash: &'a [u8; 32], + maker_secret_hash: &'a [u8; 32], funding_time_lock: u64, payment_time_lock: u64, } @@ -191,8 +191,8 @@ impl EthCoin { amount: payment_amount, dex_fee, receiver: self.my_addr().await, - taker_secret_hash: args.taker_secret_hash, - maker_secret_hash: args.maker_secret_hash, + taker_secret_hash: args.taker_secret_hash.try_into()?, + maker_secret_hash: args.maker_secret_hash.try_into()?, funding_time_lock: args.funding_time_lock, payment_time_lock: args.payment_time_lock, } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index b3698c9be6..7c1538a68f 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -72,6 +72,7 @@ use parking_lot::Mutex as PaMutex; use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::{self as json, Value as Json}; +use std::array::TryFromSliceError; use std::cmp::Ordering; use std::collections::hash_map::{HashMap, RawEntryMut}; use std::collections::HashSet; @@ -1430,7 +1431,7 @@ pub enum ValidateSwapV2TxError { /// Indicates that overflow occurred, either while calculating a total payment or converting the timelock. Overflow(String), /// Internal error - #[from_stringify("ethabi::Error")] + #[from_stringify("ethabi::Error", "TryFromSliceError")] Internal(String), /// Payment transaction is in unexpected state. E.g., `Uninitialized` instead of `PaymentSent` for ETH payment. UnexpectedPaymentState(String), From ed023922aa5ada0d4ff592279e2a4bad1453e514 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 5 Nov 2024 12:44:23 +0700 Subject: [PATCH 37/38] review: update payment state index consts names --- mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs | 4 ++-- mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) 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 6a52fa3fa4..8837b8ce0d 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 @@ -25,7 +25,7 @@ const ERC20_MAKER_PAYMENT: &str = "erc20MakerPayment"; /// uint32 paymentLockTime; /// MakerPaymentState state; /// } -const MAKER_PAYMENT_STATE_INDX: usize = 2; +const MAKER_PAYMENT_STATE_INDEX: usize = 2; struct MakerPaymentArgs { taker_address: Address, @@ -142,7 +142,7 @@ impl EthCoin { Token::FixedBytes(swap_id.clone()), &MAKER_SWAP_V2, EthPaymentType::MakerPayments, - MAKER_PAYMENT_STATE_INDX, + MAKER_PAYMENT_STATE_INDEX, ) .await?; 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 fe07ab9953..8dd686e064 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 @@ -29,7 +29,7 @@ const TAKER_PAYMENT_APPROVE: &str = "takerPaymentApprove"; /// uint32 paymentLockTime; /// TakerPaymentState state; /// } -const TAKER_PAYMENT_STATE_INDX: usize = 3; +const TAKER_PAYMENT_STATE_INDEX: usize = 3; struct TakerFundingArgs { dex_fee: U256, @@ -164,7 +164,7 @@ impl EthCoin { Token::FixedBytes(swap_id.clone()), &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - TAKER_PAYMENT_STATE_INDX, + TAKER_PAYMENT_STATE_INDEX, ) .await?; @@ -241,7 +241,7 @@ impl EthCoin { decoded[0].clone(), &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - TAKER_PAYMENT_STATE_INDX, + TAKER_PAYMENT_STATE_INDEX, ) .await ); @@ -398,7 +398,7 @@ impl EthCoin { decoded[0].clone(), // id from takerPaymentApprove &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - TAKER_PAYMENT_STATE_INDX, + TAKER_PAYMENT_STATE_INDEX, ) .await .map_err(|e| SearchForFundingSpendErr::Internal(ERRL!("{}", e)))?; @@ -430,7 +430,7 @@ impl EthCoin { decoded[0].clone(), &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - TAKER_PAYMENT_STATE_INDX, + TAKER_PAYMENT_STATE_INDEX, ) .await ); @@ -473,7 +473,7 @@ impl EthCoin { decoded[0].clone(), // id from spendTakerPayment &TAKER_SWAP_V2, EthPaymentType::TakerPayments, - TAKER_PAYMENT_STATE_INDX, + TAKER_PAYMENT_STATE_INDEX, ) .await?; if taker_status == U256::from(TakerPaymentStateV2::MakerSpent as u8) { From 13010845fbbac79f313afb37cbbe2918d606ad3e Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 7 Nov 2024 19:28:10 +0700 Subject: [PATCH 38/38] review: remove redundant validation --- mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs | 13 +++++++------ mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs | 13 +++++++------ mm2src/coins/eth/eth_swap_v2/mod.rs | 12 +----------- 3 files changed, 15 insertions(+), 23 deletions(-) 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 8837b8ce0d..3089604ede 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 @@ -1,4 +1,4 @@ -use super::{validate_from_to_and_status, validate_payment_args, EthPaymentType, PaymentMethod, PrepareTxDataError, +use super::{validate_amount, validate_from_to_and_status, EthPaymentType, PaymentMethod, PrepareTxDataError, ZERO_VALUE}; use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, @@ -132,9 +132,9 @@ impl EthCoin { ValidatePaymentError::InternalError("Expected swap_v2_contracts to be Some, but found None".to_string()) })? .maker_swap_v2_contract; - validate_payment_args(args.taker_secret_hash, args.maker_secret_hash, &args.amount) - .map_to_mm(ValidatePaymentError::InternalError)?; - let maker_address = public_to_address(args.maker_pub); + 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 maker_status = self .payment_status_v2( @@ -155,6 +155,7 @@ impl EthCoin { args.maker_payment_tx.tx_hash() )) })?; + let maker_address = public_to_address(args.maker_pub); validate_from_to_and_status( tx_from_rpc, maker_address, @@ -169,8 +170,8 @@ impl EthCoin { swap_id, amount, taker: self.my_addr().await, - taker_secret_hash: args.taker_secret_hash.try_into()?, - maker_secret_hash: args.maker_secret_hash.try_into()?, + taker_secret_hash, + maker_secret_hash, payment_time_lock: args.time_lock, } }; 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 8dd686e064..fea91b0408 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 @@ -1,4 +1,4 @@ -use super::{check_decoded_length, validate_from_to_and_status, validate_payment_args, validate_payment_state, +use super::{check_decoded_length, validate_amount, validate_from_to_and_status, validate_payment_state, EthPaymentType, PaymentMethod, PrepareTxDataError, ZERO_VALUE}; use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, @@ -154,9 +154,9 @@ impl EthCoin { ValidateSwapV2TxError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) })? .taker_swap_v2_contract; - validate_payment_args(args.taker_secret_hash, args.maker_secret_hash, &args.trading_amount) - .map_err(ValidateSwapV2TxError::Internal)?; - let taker_address = public_to_address(args.taker_pub); + let taker_secret_hash = args.taker_secret_hash.try_into()?; + let maker_secret_hash = args.maker_secret_hash.try_into()?; + validate_amount(&args.trading_amount).map_err(ValidateSwapV2TxError::Internal)?; let swap_id = self.etomic_swap_id_v2(args.payment_time_lock, args.maker_secret_hash); let taker_status = self .payment_status_v2( @@ -175,6 +175,7 @@ impl EthCoin { args.funding_tx.tx_hash() )) })?; + let taker_address = public_to_address(args.taker_pub); validate_from_to_and_status( tx_from_rpc, taker_address, @@ -191,8 +192,8 @@ impl EthCoin { amount: payment_amount, dex_fee, receiver: self.my_addr().await, - taker_secret_hash: args.taker_secret_hash.try_into()?, - maker_secret_hash: args.maker_secret_hash.try_into()?, + taker_secret_hash, + maker_secret_hash, funding_time_lock: args.funding_time_lock, payment_time_lock: args.payment_time_lock, } diff --git a/mm2src/coins/eth/eth_swap_v2/mod.rs b/mm2src/coins/eth/eth_swap_v2/mod.rs index ff31330ce3..798a232d56 100644 --- a/mm2src/coins/eth/eth_swap_v2/mod.rs +++ b/mm2src/coins/eth/eth_swap_v2/mod.rs @@ -154,20 +154,10 @@ pub(crate) fn validate_from_to_and_status( } // TODO validate premium when add its support in swap_v2 -fn validate_payment_args<'a>( - taker_secret_hash: &'a [u8], - maker_secret_hash: &'a [u8], - trading_amount: &BigDecimal, -) -> Result<(), String> { +fn validate_amount(trading_amount: &BigDecimal) -> Result<(), String> { if !trading_amount.is_positive() { return Err("trading_amount must be a positive value".to_string()); } - if taker_secret_hash.len() != 32 { - return Err("taker_secret_hash must be 32 bytes".to_string()); - } - if maker_secret_hash.len() != 32 { - return Err("maker_secret_hash must be 32 bytes".to_string()); - } Ok(()) }