diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0d50f70024..8ad2ab0bb6 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -2248,7 +2248,7 @@ impl MarketCoinOps for EthCoin { } } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { macro_rules! update_status_with_error { ($status: ident, $error: ident) => { match $error.get_inner() { @@ -2319,7 +2319,8 @@ impl MarketCoinOps for EthCoin { Ok(conf) => { if conf == confirmed_at { status.append(" Confirmed."); - break Ok(()); + // Let's avoid risking additional errors by calling `current_block` and instead return required_confirms + break Ok(required_confirms.as_u64()); } }, Err(e) => { diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 2feb7ef014..b9557185a5 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -1120,7 +1120,7 @@ impl MarketCoinOps for LightningCoin { // Todo: Add waiting for confirmations logic for the case of if the channel is closed and the htlc can be claimed on-chain // Todo: The above is postponed and might not be needed after this issue is resolved https://github.com/lightningdevkit/rust-lightning/issues/2017 - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { let payment_hash = try_f!(payment_hash_from_slice(&input.payment_tx).map_err(|e| e.to_string())); let payment_hex = hex::encode(payment_hash.0); @@ -1139,7 +1139,7 @@ impl MarketCoinOps for LightningCoin { Ok(Some(payment)) => { match payment.payment_type { PaymentType::OutboundPayment { .. } => match payment.status { - HTLCStatus::Pending | HTLCStatus::Succeeded => return Ok(()), + HTLCStatus::Pending | HTLCStatus::Succeeded => return Ok(1u64), HTLCStatus::Claimable => { return ERR!( "Payment {} has an invalid status of {} in the db", @@ -1153,7 +1153,7 @@ impl MarketCoinOps for LightningCoin { HTLCStatus::Failed => return ERR!("Lightning swap payment {} failed", payment_hex), }, PaymentType::InboundPayment => match payment.status { - HTLCStatus::Claimable | HTLCStatus::Succeeded => return Ok(()), + HTLCStatus::Claimable | HTLCStatus::Succeeded => return Ok(1u64), HTLCStatus::Pending => info!("Payment {} not received yet!", payment_hex), HTLCStatus::Failed => return ERR!("Lightning swap payment {} failed", payment_hex), }, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 4e5d281b33..00f7752f6a 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1979,7 +1979,8 @@ pub trait MarketCoinOps { /// Signs raw utxo transaction in hexadecimal format as input and returns signed transaction in hexadecimal format async fn sign_raw_tx(&self, args: &SignRawTransactionRequest) -> RawTransactionResult; - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send>; + /// Wait for confirmations and return confirmation number + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send>; fn wait_for_htlc_tx_spend(&self, args: WaitForHTLCTxSpendArgs<'_>) -> TransactionFut; diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 3ee9e7761b..554a84c85a 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1250,7 +1250,7 @@ impl MarketCoinOps for Qrc20Coin { utxo_common::sign_raw_tx(self, args).await } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { let tx: UtxoTx = try_fus!(deserialize(input.payment_tx.as_slice()).map_err(|e| ERRL!("{:?}", e))); let selfi = self.clone(); let fut = async move { diff --git a/mm2src/coins/qrc20/swap.rs b/mm2src/coins/qrc20/swap.rs index a6162f6421..77f68576d4 100644 --- a/mm2src/coins/qrc20/swap.rs +++ b/mm2src/coins/qrc20/swap.rs @@ -374,9 +374,9 @@ impl Qrc20Coin { requires_nota: bool, wait_until: u64, check_every: u64, - ) -> Result<(), String> { + ) -> Result { let tx_hash = H256Json::from(qtum_tx.hash().reversed()); - try_s!( + let confirmations = try_s!( self.utxo .rpc_client .wait_for_confirmations( @@ -415,7 +415,7 @@ impl Qrc20Coin { try_s!(check_if_contract_call_completed(&receipt)); } - Ok(()) + Ok(confirmations) } /// Generate `ContractCallOutput` outputs required to send a swap payment. diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index bc5e12f6ff..958186c283 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -2560,7 +2560,7 @@ impl MarketCoinOps for TendermintCoin { }) } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { // Sanity check let _: TxRaw = try_fus!(Message::decode(input.payment_tx.as_slice())); @@ -2581,7 +2581,8 @@ impl MarketCoinOps for TendermintCoin { if let Some(tx_status_code) = tx_status_code { return match tx_status_code { - cosmrs::tendermint::abci::Code::Ok => Ok(()), + // Tendermint uses Byzantine Fault Tolerance (BFT), achieve instant finality once a block is committed. + cosmrs::tendermint::abci::Code::Ok => Ok(1u64), cosmrs::tendermint::abci::Code::Err(err_code) => Err(format!( "Got error code: '{}' for tx: '{}'. Broadcasted tx isn't valid.", err_code, tx_hash diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index 3e63589926..2d36c3fea1 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -434,7 +434,7 @@ impl MarketCoinOps for TendermintToken { }) } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { self.platform_coin.wait_for_confirmations(input) } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index a5eaff2220..5672672821 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -88,7 +88,10 @@ impl MarketCoinOps for TestCoin { #[inline(always)] async fn sign_raw_tx(&self, _args: &SignRawTransactionRequest) -> RawTransactionResult { unimplemented!() } - fn wait_for_confirmations(&self, _input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations( + &self, + _input: ConfirmPaymentInput, + ) -> Box + Send> { unimplemented!() } diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index f2cf7b4251..6c7b678cf7 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -1225,7 +1225,7 @@ impl MarketCoinOps for BchCoin { utxo_common::sign_raw_tx(self, args).await } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { utxo_common::wait_for_confirmations(&self.utxo_arc, input) } diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index d3442d6690..070d1f9acb 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -845,7 +845,7 @@ impl MarketCoinOps for QtumCoin { utxo_common::sign_raw_tx(self, args).await } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { utxo_common::wait_for_confirmations(&self.utxo_arc, input) } diff --git a/mm2src/coins/utxo/rpc_clients.rs b/mm2src/coins/utxo/rpc_clients.rs index f5150e4a9a..98c3e3afa9 100644 --- a/mm2src/coins/utxo/rpc_clients.rs +++ b/mm2src/coins/utxo/rpc_clients.rs @@ -163,7 +163,7 @@ impl UtxoRpcClientEnum { requires_notarization: bool, wait_until: u64, check_every: u64, - ) -> Box + Send> { + ) -> Box + Send> { let selfi = self.clone(); let mut tx_not_found_retries = TX_NOT_FOUND_RETRIES; let fut = async move { @@ -185,7 +185,7 @@ impl UtxoRpcClientEnum { t.rawconfirmations.unwrap_or(t.confirmations) }; if tx_confirmations >= confirmations { - return Ok(()); + return Ok(tx_confirmations as u64); } else { info!( "Waiting for tx {:?} confirmations, now {}, required {}, requires_notarization {}", diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index c559449c22..6fc32d8c34 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1184,7 +1184,7 @@ impl MarketCoinOps for SlpToken { utxo_common::sign_raw_tx(self, args).await } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { self.platform_coin.wait_for_confirmations(input) } diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 12c18f602c..171b03b44e 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -2844,7 +2844,7 @@ async fn sign_raw_utxo_tx + UtxoTxGenerationOps>( pub fn wait_for_confirmations( coin: &UtxoCoinFields, input: ConfirmPaymentInput, -) -> Box + Send> { +) -> Box + Send> { let mut tx: UtxoTx = try_fus!(deserialize(input.payment_tx.as_slice()).map_err(|e| ERRL!("{:?}", e))); tx.tx_hash_algo = coin.tx_hash_algo; coin.rpc_client.wait_for_confirmations( diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 6baaf9d180..d1798dff69 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -881,7 +881,7 @@ impl MarketCoinOps for UtxoStandardCoin { utxo_common::sign_raw_tx(self, args).await } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { utxo_common::wait_for_confirmations(&self.utxo_arc, input) } diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 81d0aca85c..a18f7a7c91 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1157,7 +1157,7 @@ impl MarketCoinOps for ZCoin { utxo_common::sign_raw_tx(self, args).await } - fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { + fn wait_for_confirmations(&self, input: ConfirmPaymentInput) -> Box + Send> { utxo_common::wait_for_confirmations(self.as_ref(), input) } diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index f2b59fad22..bb8cfb7dae 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1826,10 +1826,9 @@ impl TakerSwap { info!("Maker payment spend tx {:02x}", tx_hash); // we should wait for only one confirmation to make sure spend maker payment transaction is not failed - let confirmations = std::cmp::min(1, self.r().data.maker_payment_confirmations); let confirm_maker_payment_spend_input = ConfirmPaymentInput { payment_tx: transaction.tx_hex(), - confirmations, + confirmations: std::cmp::min(1, self.r().data.maker_payment_confirmations), requires_nota: self.r().data.maker_payment_requires_nota.unwrap_or(false), wait_until: self.wait_refund_until(), check_every: WAIT_CONFIRM_INTERVAL_SEC, @@ -1837,14 +1836,17 @@ impl TakerSwap { let wait_fut = self .maker_coin .wait_for_confirmations(confirm_maker_payment_spend_input); - if let Err(err) = wait_fut.compat().await { - return Ok((Some(TakerSwapCommand::Finish), vec![ - TakerSwapEvent::MakerPaymentSpendFailed( - ERRL!("!wait for maker payment spend confirmations: {}", err).into(), - ), - ])); - } - info!("Maker payment spend confirmed"); + let confirmations = match wait_fut.compat().await { + Ok(conf) => conf, + Err(err) => { + return Ok((Some(TakerSwapCommand::Finish), vec![ + TakerSwapEvent::MakerPaymentSpendFailed( + ERRL!("!wait for maker payment spend confirmations: {}", err).into(), + ), + ])); + }, + }; + info!("Maker payment spend confirmed. Confirmation number: {}", confirmations); let tx_ident = TransactionIdentifier { tx_hex: BytesJson::from(transaction.tx_hex()),