diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index a3f523f98b..51fc2cd8bd 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -67,7 +67,8 @@ use super::{coin_conf, AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinPr TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, VerificationError, - VerificationResult, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, WithdrawResult}; + VerificationResult, WatcherValidatePaymentInput, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, + WithdrawResult}; pub use rlp; @@ -791,6 +792,21 @@ impl SwapOps for EthCoin { ) } + fn send_taker_spends_maker_payment_preimage(&self, _preimage: &[u8], _secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -978,6 +994,13 @@ impl SwapOps for EthCoin { ) } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 21735e84ae..a836916279 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -25,7 +25,7 @@ use crate::{BalanceFut, CoinBalance, FeeApproxStage, FoundSwapTxSpend, HistorySy SignatureError, SignatureResult, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionEnum, TransactionFut, TxMarshalingErr, UnexpectedDerivationMethod, UtxoStandardCoin, ValidateAddressResult, ValidatePaymentInput, VerificationError, VerificationResult, - WithdrawError, WithdrawFut, WithdrawRequest}; + WatcherValidatePaymentInput, WithdrawError, WithdrawFut, WithdrawRequest}; use async_trait::async_trait; use bitcoin::hashes::Hash; use bitcoin_hashes::sha256::Hash as Sha256; @@ -314,6 +314,17 @@ impl SwapOps for LightningCoin { unimplemented!() } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, _maker_payment_tx: &[u8], @@ -326,6 +337,10 @@ impl SwapOps for LightningCoin { unimplemented!() } + fn send_taker_spends_maker_payment_preimage(&self, _preimage: &[u8], _secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, _taker_payment_tx: &[u8], @@ -376,6 +391,13 @@ impl SwapOps for LightningCoin { unimplemented!() } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, _time_lock: u32, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index d7c6003a58..cfa5f542cd 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -434,6 +434,18 @@ pub enum NegotiateSwapContractAddrErr { NoOtherAddrAndNoFallback, } +#[derive(Clone, Debug)] +pub struct WatcherValidatePaymentInput { + pub payment_tx: Vec, + pub time_lock: u32, + pub taker_pub: Vec, + pub maker_pub: Vec, + pub secret_hash: Vec, + pub amount: BigDecimal, + pub try_spv_proof_until: u64, + pub confirmations: u64, +} + #[derive(Clone, Debug)] pub struct ValidatePaymentInput { pub payment_tx: Vec, @@ -492,6 +504,15 @@ pub trait SwapOps { swap_unique_data: &[u8], ) -> TransactionFut; + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut; + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -502,6 +523,8 @@ pub trait SwapOps { swap_unique_data: &[u8], ) -> TransactionFut; + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut; + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -536,6 +559,11 @@ pub trait SwapOps { fn validate_taker_payment(&self, input: ValidatePaymentInput) -> Box + Send>; + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send>; + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 6a96c4fd3f..08463ff37a 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -18,8 +18,8 @@ use crate::{BalanceError, BalanceFut, CoinBalance, FeeApproxStage, FoundSwapTxSp SearchForSwapTxSpendInput, SignatureResult, SwapOps, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TransactionType, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, - ValidatePaymentInput, VerificationResult, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest, - WithdrawResult}; + ValidatePaymentInput, VerificationResult, WatcherValidatePaymentInput, WithdrawError, WithdrawFee, + WithdrawFut, WithdrawRequest, WithdrawResult}; use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use chain::TransactionOutput; @@ -793,6 +793,17 @@ impl SwapOps for Qrc20Coin { Box::new(fut.boxed().compat()) } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -815,6 +826,10 @@ impl SwapOps for Qrc20Coin { Box::new(fut.boxed().compat()) } + fn send_taker_spends_maker_payment_preimage(&self, _preimage: &[u8], _secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -928,6 +943,13 @@ impl SwapOps for Qrc20Coin { Box::new(fut.boxed().compat()) } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/solana.rs b/mm2src/coins/solana.rs index 5a487851b6..a13a88a79c 100644 --- a/mm2src/coins/solana.rs +++ b/mm2src/coins/solana.rs @@ -5,7 +5,8 @@ use crate::{BalanceError, BalanceFut, FeeApproxStage, FoundSwapTxSpend, Negotiat RawTransactionFut, RawTransactionRequest, SearchForSwapTxSpendInput, SignatureResult, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionFut, TransactionType, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, - VerificationResult, WithdrawError, WithdrawFut, WithdrawRequest, WithdrawResult}; + VerificationResult, WatcherValidatePaymentInput, WithdrawError, WithdrawFut, WithdrawRequest, + WithdrawResult}; use async_trait::async_trait; use base58::ToBase58; use bincode::{deserialize, serialize}; @@ -489,6 +490,17 @@ impl SwapOps for SolanaCoin { unimplemented!() } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -501,6 +513,10 @@ impl SwapOps for SolanaCoin { unimplemented!() } + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -545,6 +561,13 @@ impl SwapOps for SolanaCoin { unimplemented!() } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/solana/spl.rs b/mm2src/coins/solana/spl.rs index de7639647c..c40b99ac28 100644 --- a/mm2src/coins/solana/spl.rs +++ b/mm2src/coins/solana/spl.rs @@ -5,7 +5,8 @@ use crate::{BalanceFut, FeeApproxStage, FoundSwapTxSpend, NegotiateSwapContractA RawTransactionRequest, SearchForSwapTxSpendInput, SignatureResult, SolanaCoin, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionFut, TransactionType, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, - VerificationResult, WithdrawError, WithdrawFut, WithdrawRequest, WithdrawResult}; + VerificationResult, WatcherValidatePaymentInput, WithdrawError, WithdrawFut, WithdrawRequest, + WithdrawResult}; use async_trait::async_trait; use bincode::serialize; use common::{async_blocking, now_ms}; @@ -323,6 +324,17 @@ impl SwapOps for SplToken { unimplemented!() } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -335,6 +347,10 @@ impl SwapOps for SplToken { unimplemented!() } + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -379,6 +395,13 @@ impl SwapOps for SplToken { unimplemented!() } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 7cc9cb3d2a..8fc7664886 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -9,8 +9,8 @@ use crate::{big_decimal_from_sat_unsigned, BalanceError, BalanceFut, BigDecimal, RawTransactionFut, RawTransactionRequest, SearchForSwapTxSpendInput, SignatureResult, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionEnum, TransactionFut, TransactionType, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, - ValidateAddressResult, ValidatePaymentInput, VerificationResult, WithdrawError, WithdrawFut, - WithdrawRequest}; + ValidateAddressResult, ValidatePaymentInput, VerificationResult, WatcherValidatePaymentInput, + WithdrawError, WithdrawFut, WithdrawRequest}; use async_trait::async_trait; use bitcrypto::sha256; use common::{get_utc_timestamp, Future01CompatExt}; @@ -659,6 +659,17 @@ impl SwapOps for TendermintCoin { todo!() } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -671,6 +682,10 @@ impl SwapOps for TendermintCoin { todo!() } + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -715,6 +730,13 @@ impl SwapOps for TendermintCoin { todo!() } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index d6ff8a1d67..2c397a6874 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -3,7 +3,7 @@ use super::{CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, RawTransaction use crate::{BalanceFut, CanRefundHtlc, FeeApproxStage, FoundSwapTxSpend, NegotiateSwapContractAddrErr, SearchForSwapTxSpendInput, SignatureResult, TradePreimageFut, TradePreimageResult, TradePreimageValue, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, - VerificationResult, WithdrawFut, WithdrawRequest}; + VerificationResult, WatcherValidatePaymentInput, WithdrawFut, WithdrawRequest}; use async_trait::async_trait; use futures01::Future; use keys::KeyPair; @@ -135,6 +135,17 @@ impl SwapOps for TestCoin { unimplemented!() } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -147,6 +158,10 @@ impl SwapOps for TestCoin { unimplemented!() } + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -197,6 +212,13 @@ impl SwapOps for TestCoin { unimplemented!() } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index 3f58fd53b5..79087b71df 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -12,7 +12,7 @@ use crate::{BlockHeightAndTime, CanRefundHtlc, CoinBalance, CoinProtocol, CoinWi NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, RawTransactionFut, RawTransactionRequest, SearchForSwapTxSpendInput, SignatureResult, SwapOps, TradePreimageValue, TransactionFut, TransactionType, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, - VerificationResult, WithdrawFut}; + VerificationResult, WatcherValidatePaymentInput, WithdrawFut}; use common::log::warn; use derive_more::Display; use futures::{FutureExt, TryFutureExt}; @@ -871,6 +871,24 @@ impl SwapOps for BchCoin { ) } + fn create_taker_spends_maker_payment_preimage( + &self, + maker_payment_tx: &[u8], + time_lock: u32, + maker_pub: &[u8], + secret_hash: &[u8], + swap_unique_data: &[u8], + ) -> TransactionFut { + utxo_common::create_taker_spends_maker_payment_preimage( + self.clone(), + maker_payment_tx, + time_lock, + maker_pub, + secret_hash, + swap_unique_data, + ) + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -890,6 +908,10 @@ impl SwapOps for BchCoin { ) } + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut { + utxo_common::send_taker_spends_maker_payment_preimage(self.clone(), preimage, secret) + } + fn send_taker_refunds_payment( &self, taker_tx: &[u8], @@ -960,6 +982,13 @@ impl SwapOps for BchCoin { utxo_common::validate_taker_payment(self, input) } + fn watcher_validate_taker_payment( + &self, + input: WatcherValidatePaymentInput, + ) -> Box + Send> { + utxo_common::watcher_validate_taker_payment(self, input) + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 2d61bd5fe9..5ccd3c0d97 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -24,8 +24,8 @@ use crate::utxo::utxo_tx_history_v2::{UtxoMyAddressesHistoryError, UtxoTxDetails use crate::{eth, CanRefundHtlc, CoinBalance, CoinWithDerivationMethod, DelegationError, DelegationFut, GetWithdrawSenderAddress, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, SearchForSwapTxSpendInput, SignatureResult, StakingInfosFut, SwapOps, TradePreimageValue, TransactionFut, TxMarshalingErr, - UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, VerificationResult, WithdrawFut, - WithdrawSenderAddress}; + UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, VerificationResult, + WatcherValidatePaymentInput, WithdrawFut, WithdrawSenderAddress}; use crypto::Bip44Chain; use ethereum_types::H160; use futures::{FutureExt, TryFutureExt}; @@ -569,6 +569,24 @@ impl SwapOps for QtumCoin { ) } + fn create_taker_spends_maker_payment_preimage( + &self, + maker_payment_tx: &[u8], + time_lock: u32, + maker_pub: &[u8], + secret_hash: &[u8], + swap_unique_data: &[u8], + ) -> TransactionFut { + utxo_common::create_taker_spends_maker_payment_preimage( + self.clone(), + maker_payment_tx, + time_lock, + maker_pub, + secret_hash, + swap_unique_data, + ) + } + fn send_taker_spends_maker_payment( &self, maker_tx: &[u8], @@ -588,6 +606,10 @@ impl SwapOps for QtumCoin { ) } + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut { + utxo_common::send_taker_spends_maker_payment_preimage(self.clone(), preimage, secret) + } + fn send_taker_refunds_payment( &self, taker_tx: &[u8], @@ -658,6 +680,13 @@ impl SwapOps for QtumCoin { utxo_common::validate_taker_payment(self, input) } + fn watcher_validate_taker_payment( + &self, + input: WatcherValidatePaymentInput, + ) -> Box + Send> { + utxo_common::watcher_validate_taker_payment(self, input) + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 77517e32c3..633a4fbf89 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -17,8 +17,8 @@ use crate::{BalanceFut, CoinBalance, FeeApproxStage, FoundSwapTxSpend, HistorySy RawTransactionRequest, SearchForSwapTxSpendInput, SignatureResult, SwapOps, TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, - ValidateAddressResult, ValidatePaymentInput, VerificationError, VerificationResult, WithdrawError, - WithdrawFee, WithdrawFut, WithdrawRequest}; + ValidateAddressResult, ValidatePaymentInput, VerificationError, VerificationResult, + WatcherValidatePaymentInput, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest}; use async_trait::async_trait; use bitcrypto::dhash160; use chain::constants::SEQUENCE_FINAL; @@ -1273,6 +1273,17 @@ impl SwapOps for SlpToken { Box::new(fut.boxed().compat()) } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -1298,6 +1309,10 @@ impl SwapOps for SlpToken { Box::new(fut.boxed().compat()) } + fn send_taker_spends_maker_payment_preimage(&self, _preimage: &[u8], _secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -1394,6 +1409,13 @@ impl SwapOps for SlpToken { Box::new(fut.boxed().compat()) } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index d2b5bdb44c..c39b9b1b72 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -13,8 +13,8 @@ use crate::utxo::utxo_withdraw::{InitUtxoWithdraw, StandardUtxoWithdraw, UtxoWit use crate::{CanRefundHtlc, CoinBalance, CoinWithDerivationMethod, GetWithdrawSenderAddress, HDAccountAddressId, RawTransactionError, RawTransactionRequest, RawTransactionRes, SearchForSwapTxSpendInput, SignatureError, SignatureResult, SwapOps, TradePreimageValue, TransactionFut, TxFeeDetails, TxMarshalingErr, - ValidateAddressResult, ValidatePaymentInput, VerificationError, VerificationResult, WithdrawFrom, - WithdrawResult, WithdrawSenderAddress}; + ValidateAddressResult, ValidatePaymentInput, VerificationError, VerificationResult, + WatcherValidatePaymentInput, WithdrawFrom, WithdrawResult, WithdrawSenderAddress}; use bitcrypto::dhash256; pub use bitcrypto::{dhash160, sha256, ChecksumType}; use chain::constants::SEQUENCE_FINAL; @@ -1042,6 +1042,9 @@ pub struct P2SHSpendingTxInput<'a> { } pub async fn p2sh_spending_tx(coin: &T, input: P2SHSpendingTxInput<'_>) -> Result { + if input.prev_transaction.outputs.is_empty() { + return ERR!("Transaction doesn't have any output"); + } let lock_time = try_s!(coin.p2sh_tx_locktime(input.lock_time).await); let n_time = if coin.as_ref().conf.is_pos { Some((now_ms() / 1000) as u32) @@ -1219,6 +1222,10 @@ pub fn send_maker_spends_taker_payment( let my_address = try_tx_fus!(coin.as_ref().derivation_method.iguana_or_err()).clone(); let mut prev_transaction: UtxoTx = try_tx_fus!(deserialize(taker_payment_tx).map_err(|e| ERRL!("{:?}", e))); prev_transaction.tx_hash_algo = coin.as_ref().tx_hash_algo; + drop_mutability!(prev_transaction); + if prev_transaction.outputs.is_empty() { + return try_tx_fus!(TX_PLAIN_ERR!("Transaction doesn't have any output")); + } let key_pair = coin.derive_htlc_key_pair(swap_unique_data); let script_data = Builder::default() @@ -1234,6 +1241,13 @@ pub fn send_maker_spends_taker_payment( .into(); let fut = async move { let fee = try_tx_s!(coin.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE).await); + if fee >= prev_transaction.outputs[0].value { + return TX_PLAIN_ERR!( + "HTLC spend fee {} is greater than transaction output {}", + fee, + prev_transaction.outputs[0].value + ); + } let script_pubkey = output_script(&my_address, ScriptType::P2PKH).to_bytes(); let output = TransactionOutput { value: prev_transaction.outputs[0].value - fee, @@ -1259,6 +1273,106 @@ pub fn send_maker_spends_taker_payment( Box::new(fut.boxed().compat()) } +pub fn send_taker_spends_maker_payment_preimage( + coin: T, + preimage: &[u8], + secret: &[u8], +) -> TransactionFut { + let mut transaction: UtxoTx = try_tx_fus!(deserialize(preimage).map_err(|e| ERRL!("{:?}", e))); + if transaction.inputs.is_empty() { + return try_tx_fus!(TX_PLAIN_ERR!("Transaction doesn't have any input")); + } + let script = Script::from(transaction.inputs[0].script_sig.clone()); + let mut instructions = script.iter(); + + let instruction_1 = try_tx_fus!(try_tx_fus!(instructions.next().ok_or("Instruction not found"))); + let instruction_2 = try_tx_fus!(try_tx_fus!(instructions.next().ok_or("Instruction not found"))); + + let script_sig = try_tx_fus!(instruction_1 + .data + .ok_or("No script signature in the taker spends maker payment preimage")); + let redeem_script = try_tx_fus!(instruction_2 + .data + .ok_or("No redeem script in the taker spends maker payment preimage")); + let script_data = Builder::default() + .push_data(secret) + .push_opcode(Opcode::OP_0) + .into_script(); + + let mut resulting_script = Builder::default().push_data(script_sig).into_bytes(); + resulting_script.extend_from_slice(&script_data); + let redeem_part = Builder::default().push_data(redeem_script).into_bytes(); + resulting_script.extend_from_slice(&redeem_part); + + transaction.inputs[0].script_sig = resulting_script; + + let fut = async move { + let tx_fut = coin.as_ref().rpc_client.send_transaction(&transaction).compat(); + try_tx_s!(tx_fut.await, transaction); + + Ok(transaction.into()) + }; + + Box::new(fut.boxed().compat()) +} + +pub fn create_taker_spends_maker_payment_preimage( + coin: T, + maker_payment_tx: &[u8], + time_lock: u32, + maker_pub: &[u8], + secret_hash: &[u8], + swap_unique_data: &[u8], +) -> TransactionFut { + let my_address = try_tx_fus!(coin.as_ref().derivation_method.iguana_or_err()).clone(); + let mut prev_transaction: UtxoTx = try_tx_fus!(deserialize(maker_payment_tx).map_err(|e| ERRL!("{:?}", e))); + prev_transaction.tx_hash_algo = coin.as_ref().tx_hash_algo; + drop_mutability!(prev_transaction); + if prev_transaction.outputs.is_empty() { + return try_tx_fus!(TX_PLAIN_ERR!("Transaction doesn't have any output")); + } + + let key_pair = coin.derive_htlc_key_pair(swap_unique_data); + + let script_data = Builder::default().into_script(); + let redeem_script = payment_script( + time_lock, + secret_hash, + &try_tx_fus!(Public::from_slice(maker_pub)), + key_pair.public(), + ) + .into(); + let fut = async move { + let fee = try_tx_s!(coin.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE).await); + if fee >= prev_transaction.outputs[0].value { + return TX_PLAIN_ERR!( + "HTLC spend fee {} is greater than transaction output {}", + fee, + prev_transaction.outputs[0].value + ); + } + let script_pubkey = output_script(&my_address, ScriptType::P2PKH).to_bytes(); + let output = TransactionOutput { + value: prev_transaction.outputs[0].value - fee, + script_pubkey, + }; + + let input = P2SHSpendingTxInput { + prev_transaction, + redeem_script, + outputs: vec![output], + script_data, + sequence: SEQUENCE_FINAL, + lock_time: time_lock, + keypair: &key_pair, + }; + let transaction = try_tx_s!(coin.p2sh_spending_tx(input).await); + + Ok(transaction.into()) + }; + Box::new(fut.boxed().compat()) +} + pub fn send_taker_spends_maker_payment( coin: T, maker_payment_tx: &[u8], @@ -1270,6 +1384,10 @@ pub fn send_taker_spends_maker_payment( let my_address = try_tx_fus!(coin.as_ref().derivation_method.iguana_or_err()).clone(); let mut prev_transaction: UtxoTx = try_tx_fus!(deserialize(maker_payment_tx).map_err(|e| ERRL!("{:?}", e))); prev_transaction.tx_hash_algo = coin.as_ref().tx_hash_algo; + drop_mutability!(prev_transaction); + if prev_transaction.outputs.is_empty() { + return try_tx_fus!(TX_PLAIN_ERR!("Transaction doesn't have any output")); + } let key_pair = coin.derive_htlc_key_pair(swap_unique_data); @@ -1286,6 +1404,13 @@ pub fn send_taker_spends_maker_payment( .into(); let fut = async move { let fee = try_tx_s!(coin.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE).await); + if fee >= prev_transaction.outputs[0].value { + return TX_PLAIN_ERR!( + "HTLC spend fee {} is greater than transaction output {}", + fee, + prev_transaction.outputs[0].value + ); + } let script_pubkey = output_script(&my_address, ScriptType::P2PKH).to_bytes(); let output = TransactionOutput { value: prev_transaction.outputs[0].value - fee, @@ -1323,6 +1448,10 @@ pub fn send_taker_refunds_payment( let mut prev_transaction: UtxoTx = try_tx_fus!(deserialize(taker_payment_tx).map_err(|e| TransactionErr::Plain(format!("{:?}", e)))); prev_transaction.tx_hash_algo = coin.as_ref().tx_hash_algo; + drop_mutability!(prev_transaction); + if prev_transaction.outputs.is_empty() { + return try_tx_fus!(TX_PLAIN_ERR!("Transaction doesn't have any output")); + } let key_pair = coin.derive_htlc_key_pair(swap_unique_data); let script_data = Builder::default().push_opcode(Opcode::OP_1).into_script(); @@ -1335,6 +1464,13 @@ pub fn send_taker_refunds_payment( .into(); let fut = async move { let fee = try_tx_s!(coin.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE).await); + if fee >= prev_transaction.outputs[0].value { + return TX_PLAIN_ERR!( + "HTLC spend fee {} is greater than transaction output {}", + fee, + prev_transaction.outputs[0].value + ); + } let script_pubkey = output_script(&my_address, ScriptType::P2PKH).to_bytes(); let output = TransactionOutput { value: prev_transaction.outputs[0].value - fee, @@ -1371,6 +1507,10 @@ pub fn send_maker_refunds_payment( let my_address = try_tx_fus!(coin.as_ref().derivation_method.iguana_or_err()).clone(); let mut prev_transaction: UtxoTx = try_tx_fus!(deserialize(maker_payment_tx).map_err(|e| ERRL!("{:?}", e))); prev_transaction.tx_hash_algo = coin.as_ref().tx_hash_algo; + drop_mutability!(prev_transaction); + if prev_transaction.outputs.is_empty() { + return try_tx_fus!(TX_PLAIN_ERR!("Transaction doesn't have any output")); + } let key_pair = coin.derive_htlc_key_pair(swap_unique_data); let script_data = Builder::default().push_opcode(Opcode::OP_1).into_script(); @@ -1383,6 +1523,13 @@ pub fn send_maker_refunds_payment( .into(); let fut = async move { let fee = try_tx_s!(coin.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE).await); + if fee >= prev_transaction.outputs[0].value { + return TX_PLAIN_ERR!( + "HTLC spend fee {} is greater than transaction output {}", + fee, + prev_transaction.outputs[0].value + ); + } let script_pubkey = output_script(&my_address, ScriptType::P2PKH).to_bytes(); let output = TransactionOutput { value: prev_transaction.outputs[0].value - fee, @@ -1590,6 +1737,27 @@ pub fn validate_maker_payment( ) } +pub fn watcher_validate_taker_payment( + coin: &T, + input: WatcherValidatePaymentInput, +) -> Box + Send> { + let mut tx: UtxoTx = try_fus!(deserialize(input.payment_tx.as_slice()).map_err(|e| ERRL!("{:?}", e))); + tx.tx_hash_algo = coin.as_ref().tx_hash_algo; + + validate_payment( + coin.clone(), + tx, + DEFAULT_SWAP_VOUT, + &try_fus!(Public::from_slice(&input.taker_pub)), + &try_fus!(Public::from_slice(&input.maker_pub)), + &input.secret_hash, + input.amount, + input.time_lock, + input.try_spv_proof_until, + input.confirmations, + ) +} + pub fn validate_taker_payment( coin: &T, input: ValidatePaymentInput, @@ -1598,6 +1766,7 @@ pub fn validate_taker_payment( tx.tx_hash_algo = coin.as_ref().tx_hash_algo; let htlc_keypair = coin.derive_htlc_key_pair(&input.unique_swap_data); + validate_payment( coin.clone(), tx, @@ -3334,6 +3503,10 @@ async fn search_for_swap_output_spend( ) -> Result, String> { let mut tx: UtxoTx = try_s!(deserialize(tx).map_err(|e| ERRL!("{:?}", e))); tx.tx_hash_algo = coin.tx_hash_algo; + drop_mutability!(tx); + if tx.outputs.is_empty() { + return ERR!("Transaction doesn't have any output"); + } let script = payment_script(time_lock, secret_hash, first_pub, second_pub); let expected_script_pubkey = Builder::build_p2sh(&dhash160(&script).into()).to_bytes(); if tx.outputs[0].script_pubkey != expected_script_pubkey { diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 685f823fe1..8afa358829 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -22,7 +22,7 @@ use crate::utxo::utxo_tx_history_v2::{UtxoMyAddressesHistoryError, UtxoTxDetails use crate::{CanRefundHtlc, CoinBalance, CoinWithDerivationMethod, GetWithdrawSenderAddress, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, SearchForSwapTxSpendInput, SignatureResult, SwapOps, TradePreimageValue, TransactionFut, TxMarshalingErr, ValidateAddressResult, ValidatePaymentInput, - VerificationResult, WithdrawFut, WithdrawSenderAddress}; + VerificationResult, WatcherValidatePaymentInput, WithdrawFut, WithdrawSenderAddress}; use crypto::Bip44Chain; use futures::{FutureExt, TryFutureExt}; use mm2_metrics::MetricsArc; @@ -330,6 +330,24 @@ impl SwapOps for UtxoStandardCoin { ) } + fn create_taker_spends_maker_payment_preimage( + &self, + maker_payment_tx: &[u8], + time_lock: u32, + maker_pub: &[u8], + secret_hash: &[u8], + swap_unique_data: &[u8], + ) -> TransactionFut { + utxo_common::create_taker_spends_maker_payment_preimage( + self.clone(), + maker_payment_tx, + time_lock, + maker_pub, + secret_hash, + swap_unique_data, + ) + } + fn send_taker_spends_maker_payment( &self, maker_tx: &[u8], @@ -349,6 +367,10 @@ impl SwapOps for UtxoStandardCoin { ) } + fn send_taker_spends_maker_payment_preimage(&self, preimage: &[u8], secret: &[u8]) -> TransactionFut { + utxo_common::send_taker_spends_maker_payment_preimage(self.clone(), preimage, secret) + } + fn send_taker_refunds_payment( &self, taker_tx: &[u8], @@ -419,6 +441,13 @@ impl SwapOps for UtxoStandardCoin { utxo_common::validate_taker_payment(self, input) } + fn watcher_validate_taker_payment( + &self, + input: WatcherValidatePaymentInput, + ) -> Box + Send> { + utxo_common::watcher_validate_taker_payment(self, input) + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index f1a37355d2..38bbd308be 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -16,7 +16,8 @@ use crate::{BalanceError, BalanceFut, CoinBalance, FeeApproxStage, FoundSwapTxSp RawTransactionRequest, SearchForSwapTxSpendInput, SignatureError, SignatureResult, SwapOps, TradeFee, TradePreimageFut, TradePreimageResult, TradePreimageValue, TransactionDetails, TransactionEnum, TransactionFut, TxFeeDetails, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, - ValidatePaymentInput, VerificationError, VerificationResult, WithdrawFut, WithdrawRequest}; + ValidatePaymentInput, VerificationError, VerificationResult, WatcherValidatePaymentInput, WithdrawFut, + WithdrawRequest}; use crate::{Transaction, WithdrawError}; use async_trait::async_trait; use bitcrypto::{dhash160, dhash256}; @@ -1126,6 +1127,17 @@ impl SwapOps for ZCoin { Box::new(fut.boxed().compat()) } + fn create_taker_spends_maker_payment_preimage( + &self, + _maker_payment_tx: &[u8], + _time_lock: u32, + _maker_pub: &[u8], + _secret_hash: &[u8], + _swap_unique_data: &[u8], + ) -> TransactionFut { + unimplemented!(); + } + fn send_taker_spends_maker_payment( &self, maker_payment_tx: &[u8], @@ -1164,6 +1176,10 @@ impl SwapOps for ZCoin { Box::new(fut.boxed().compat()) } + fn send_taker_spends_maker_payment_preimage(&self, _preimage: &[u8], _secret: &[u8]) -> TransactionFut { + unimplemented!(); + } + fn send_taker_refunds_payment( &self, taker_payment_tx: &[u8], @@ -1327,6 +1343,13 @@ impl SwapOps for ZCoin { utxo_common::validate_taker_payment(self, input) } + fn watcher_validate_taker_payment( + &self, + _input: WatcherValidatePaymentInput, + ) -> Box + Send> { + unimplemented!(); + } + fn check_if_my_payment_sent( &self, time_lock: u32, diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 51259488e9..3fa3e4dc0d 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -213,6 +213,10 @@ impl MmCtx { path.join(hex::encode(&**self.rmd160())) } + pub fn is_watcher(&self) -> bool { self.conf["is_watcher"].as_bool().unwrap_or_default() } + + pub fn use_watchers(&self) -> bool { self.conf["use_watchers"].as_bool().unwrap_or_default() } + pub fn netid(&self) -> u16 { let netid = self.conf["netid"].as_u64().unwrap_or(0); if netid > u16::MAX.into() { diff --git a/mm2src/mm2_main/src/docker_tests.rs b/mm2src/mm2_main/src/docker_tests.rs index 91cdd47d47..7344de1ea6 100644 --- a/mm2src/mm2_main/src/docker_tests.rs +++ b/mm2src/mm2_main/src/docker_tests.rs @@ -117,7 +117,7 @@ mod docker_tests { use keys::{Address, KeyPair, NetworkPrefix as CashAddrPrefix, Private}; use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; use mm2_number::{BigDecimal, MmNumber}; - use mm2_test_helpers::for_tests::{check_my_swap_status_amounts, enable_electrum}; + use mm2_test_helpers::for_tests::{check_my_swap_status_amounts, enable_electrum, Mm2TestConf}; use qrc20_tests::{qtum_docker_node, QtumDockerOps, QTUM_REGTEST_DOCKER_IMAGE}; use script::Builder; use secp256k1::SecretKey; @@ -389,19 +389,6 @@ mod docker_tests { fn rpc_client(&self) -> &UtxoRpcClientEnum { &self.coin.as_ref().rpc_client } } - /// Generate random privkey, create a UTXO coin and fill it's address with the specified balance. - fn generate_utxo_coin_with_random_privkey( - ticker: &str, - balance: BigDecimal, - ) -> (MmArc, UtxoStandardCoin, [u8; 32]) { - let priv_key = SecretKey::new(&mut rand6::thread_rng()); - let (ctx, coin) = utxo_coin_from_privkey(ticker, priv_key.as_ref()); - let timeout = 30; // timeout if test takes more than 30 seconds to run - let my_address = coin.my_address().expect("!my_address"); - fill_address(&coin, &my_address, balance, timeout); - (ctx, coin, *priv_key.as_ref()) - } - #[test] fn test_search_for_swap_tx_spend_native_was_refunded_taker() { let timeout = (now_ms() / 1000) + 120; // timeout if test takes more than 120 seconds to run @@ -1152,6 +1139,128 @@ mod docker_tests { block_on(mm_alice.stop()).unwrap(); } + #[test] + fn test_watcher_node() { + let (_ctx, _, bob_priv_key) = generate_utxo_coin_with_random_privkey("MYCOIN", 100.into()); + generate_utxo_coin_with_privkey("MYCOIN1", 100.into(), &bob_priv_key); + let (_ctx, _, alice_priv_key) = generate_utxo_coin_with_random_privkey("MYCOIN1", 100.into()); + generate_utxo_coin_with_privkey("MYCOIN", 100.into(), &alice_priv_key); + let watcher_priv_key = *SecretKey::new(&mut rand6::thread_rng()).as_ref(); + + let coins = json! ([ + {"coin":"MYCOIN","asset":"MYCOIN","txversion":4,"overwintered":1,"txfee":1000,"protocol":{"type":"UTXO"}}, + {"coin":"MYCOIN1","asset":"MYCOIN1","txversion":4,"overwintered":1,"txfee":1000,"protocol":{"type":"UTXO"}}, + ]); + + let alice_conf = + Mm2TestConf::seednode_using_watchers(&format!("0x{}", hex::encode(alice_priv_key)), &coins).conf; + let mut mm_alice = MarketMakerIt::start(alice_conf.clone(), "pass".to_string(), None).unwrap(); + let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path); + + let bob_conf = Mm2TestConf::light_node(&format!("0x{}", hex::encode(bob_priv_key)), &coins, &[&mm_alice + .ip + .to_string()]) + .conf; + let mm_bob = MarketMakerIt::start(bob_conf, "pass".to_string(), None).unwrap(); + let (_bob_dump_log, _bob_dump_dashboard) = mm_dump(&mm_bob.log_path); + + let watcher_conf = + Mm2TestConf::watcher_light_node(&format!("0x{}", hex::encode(watcher_priv_key)), &coins, &[&mm_alice + .ip + .to_string()]) + .conf; + let mut mm_watcher = MarketMakerIt::start(watcher_conf, "pass".to_string(), None).unwrap(); + let (_watcher_dump_log, _watcher_dump_dashboard) = mm_dump(&mm_watcher.log_path); + + log!("{:?}", block_on(enable_native(&mm_bob, "MYCOIN", &[]))); + log!("{:?}", block_on(enable_native(&mm_bob, "MYCOIN1", &[]))); + log!("{:?}", block_on(enable_native(&mm_alice, "MYCOIN", &[]))); + log!("{:?}", block_on(enable_native(&mm_alice, "MYCOIN1", &[]))); + log!("{:?}", block_on(enable_native(&mm_watcher, "MYCOIN", &[]))); + log!("{:?}", block_on(enable_native(&mm_watcher, "MYCOIN1", &[]))); + + let rc = block_on(mm_bob.rpc(&json! ({ + "userpass": mm_bob.userpass, + "method": "setprice", + "base": "MYCOIN", + "rel": "MYCOIN1", + "price": 25, + "max": true, + }))) + .unwrap(); + assert!(rc.0.is_success(), "!setprice: {}", rc.1); + + let rc = block_on(mm_alice.rpc(&json! ({ + "userpass": mm_alice.userpass, + "method": "buy", + "base": "MYCOIN", + "rel": "MYCOIN1", + "price": 25, + "volume": "2", + }))) + .unwrap(); + assert!(rc.0.is_success(), "!buy: {}", rc.1); + + block_on(mm_alice.wait_for_log(60., |log| log.contains("Taker payment tx hash"))).unwrap(); + block_on(mm_alice.stop()).unwrap(); + block_on(mm_watcher.wait_for_log(60., |log| log.contains("Maker payment spend tx"))).unwrap(); + thread::sleep(Duration::from_secs(5)); + + let mm_alice = MarketMakerIt::start(alice_conf, "pass".to_string(), None).unwrap(); + let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path); + + log!("{:?}", block_on(enable_native(&mm_alice, "MYCOIN", &[]))); + log!("{:?}", block_on(enable_native(&mm_alice, "MYCOIN1", &[]))); + + let rc = block_on(mm_alice.rpc(&json! ({ + "userpass": mm_alice.userpass, + "method": "my_balance", + "coin": "MYCOIN1" + }))) + .unwrap(); + assert!(rc.0.is_success(), "!my_balance: {}", rc.1); + + let json: Json = json::from_str(&rc.1).unwrap(); + let alice_mycoin1_balance = json["balance"].as_str().unwrap(); + assert_eq!(alice_mycoin1_balance, "49.93562994"); + + let rc = block_on(mm_alice.rpc(&json! ({ + "userpass": mm_alice.userpass, + "method": "my_balance", + "coin": "MYCOIN" + }))) + .unwrap(); + assert!(rc.0.is_success(), "!my_balance: {}", rc.1); + + let json: Json = json::from_str(&rc.1).unwrap(); + let alice_mycoin_balance = json["balance"].as_str().unwrap(); + assert_eq!(alice_mycoin_balance, "101.99999"); + + let rc = block_on(mm_bob.rpc(&json! ({ + "userpass": mm_bob.userpass, + "method": "my_balance", + "coin": "MYCOIN1" + }))) + .unwrap(); + assert!(rc.0.is_success(), "!my_balance: {}", rc.1); + + let json: Json = json::from_str(&rc.1).unwrap(); + let bob_mycoin1_balance = json["balance"].as_str().unwrap(); + assert_eq!(bob_mycoin1_balance, "149.99999"); + + let rc = block_on(mm_bob.rpc(&json! ({ + "userpass": mm_bob.userpass, + "method": "my_balance", + "coin": "MYCOIN" + }))) + .unwrap(); + assert!(rc.0.is_success(), "!my_balance: {}", rc.1); + + let json: Json = json::from_str(&rc.1).unwrap(); + let bob_mycoin_balance = json["balance"].as_str().unwrap(); + assert_eq!(bob_mycoin_balance, "97.99999"); + } + // https://github.com/KomodoPlatform/atomicDEX-API/issues/471 #[test] fn test_match_and_trade_setprice_max() { diff --git a/mm2src/mm2_main/src/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/src/docker_tests/docker_tests_common.rs index f17b0db32b..0c1adaaff3 100644 --- a/mm2src/mm2_main/src/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/src/docker_tests/docker_tests_common.rs @@ -259,6 +259,27 @@ pub fn utxo_coin_from_privkey(ticker: &str, priv_key: &[u8]) -> (MmArc, UtxoStan (ctx, coin) } +/// Create a UTXO coin for the given privkey and fill it's address with the specified balance. +pub fn generate_utxo_coin_with_privkey(ticker: &str, balance: BigDecimal, priv_key: &[u8]) { + let (_, coin) = utxo_coin_from_privkey(ticker, priv_key); + let timeout = 30; // timeout if test takes more than 30 seconds to run + let my_address = coin.my_address().expect("!my_address"); + fill_address(&coin, &my_address, balance, timeout); +} + +/// Generate random privkey, create a UTXO coin and fill it's address with the specified balance. +pub fn generate_utxo_coin_with_random_privkey( + ticker: &str, + balance: BigDecimal, +) -> (MmArc, UtxoStandardCoin, [u8; 32]) { + let priv_key = SecretKey::new(&mut rand6::thread_rng()); + let (ctx, coin) = utxo_coin_from_privkey(ticker, priv_key.as_ref()); + let timeout = 30; // timeout if test takes more than 30 seconds to run + let my_address = coin.my_address().expect("!my_address"); + fill_address(&coin, &my_address, balance, timeout); + (ctx, coin, *priv_key.as_ref()) +} + /// Get only one address assigned the specified label. pub fn get_address_by_label(coin: T, label: &str) -> String where diff --git a/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_expected.json b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_expected.json new file mode 100644 index 0000000000..e608903e87 --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_expected.json @@ -0,0 +1,62 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "events":[ + {"timestamp":1638984440546,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "secret":"0000000000000000000000000000000000000000000000000000000000000000", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "maker_payment_lock":1639000040, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "maker_payment_trade_fee":null, + "taker_payment_spend_trade_fee":null}}}, + {"timestamp":1638984456603,"event":{"type":"Negotiated", + "data":{ + "taker_payment_locktime":1638992240, + "taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "maker_coin_swap_contract_addr":null, + "taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984457822,"event":{"type":"TakerFeeValidated", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457822,"event":{"type":"MakerPaymentSent", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984503974,"event":{"type":"TakerPaymentReceived", + "data":{ + "tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000", + "tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}}, + {"timestamp":1638984503974,"event":{"type":"TakerPaymentWaitConfirmStarted"}}, + {"timestamp":1638984600390,"event":{"type":"TakerPaymentValidatedAndConfirmed"}}, + {"timestamp":1638984600390,"event":{"type":"TakerPaymentSpent", + "data":{ + "tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000", + "tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"}}}, + {"timestamp":1638984600390,"event":{"type":"TakerPaymentSpendConfirmStarted"}}, + {"timestamp":1638984600390,"event":{"type":"TakerPaymentSpendConfirmed"}}, + {"timestamp":1638984600390,"event":{"type":"Finished"}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":null, + "mm_version":"", + "success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"] + } \ No newline at end of file diff --git a/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_maker_expected.json b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_maker_expected.json new file mode 100644 index 0000000000..22da90ba70 --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_maker_expected.json @@ -0,0 +1,53 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "events":[ + {"timestamp":1638984440546,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "secret":"0000000000000000000000000000000000000000000000000000000000000000", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "maker_payment_lock":1639000040, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "maker_payment_trade_fee":null, + "taker_payment_spend_trade_fee":null}}}, + {"timestamp":1638984456603,"event":{"type":"Negotiated", + "data":{ + "taker_payment_locktime":1638992240, + "taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "maker_coin_swap_contract_addr":null, + "taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984457822,"event":{"type":"TakerFeeValidated", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457822,"event":{"type":"MakerPaymentSent", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984503611,"event":{"type":"TakerPaymentValidateFailed", + "data":{"error":"Origin Taker error event: MakerPaymentWaitConfirmFailed(SwapError { error: \"An error\" })"}}}, + {"timestamp":1638984503611,"event":{"type":"MakerPaymentWaitRefundStarted", + "data":{"wait_until":1639003740}}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":null, + "mm_version":"", + "success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"] +} \ No newline at end of file diff --git a/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_taker_saved.json b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_taker_saved.json new file mode 100644 index 0000000000..01ad7fa7bb --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_taker_saved.json @@ -0,0 +1,54 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "events":[ + {"timestamp":1638984440546,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "taker_payment_lock":1638992240, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_payment_wait":1638987560, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "fee_to_send_taker_fee":{"coin":"MORTY","amount":"0.00001", + "paid_from_trading_vol":false}, + "taker_payment_trade_fee":{"coin":"MORTY","amount":"0.00001", + "paid_from_trading_vol":false}, + "maker_payment_spend_trade_fee":{"coin":"RICK","amount":"0.00001","paid_from_trading_vol":true}}}}, + {"timestamp":1638984456603,"event":{"type":"Negotiated", + "data":{ + "maker_payment_locktime":1639000040, + "maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984456814,"event":{"type":"TakerFeeSent", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457822,"event":{"type":"MakerPaymentReceived", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984457826,"event":{"type":"MakerPaymentWaitConfirmStarted"}}, + {"timestamp":1638984503611,"event":{"type":"MakerPaymentWaitConfirmFailed","data":{"error":"An error"}}}, + {"timestamp":1638984503615,"event":{"type":"Finished"}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":"atomicDEX 0.5.1 iOS", + "mm_version":"1b065636a", + "success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"] +} \ No newline at end of file diff --git a/mm2src/mm2_main/src/for_tests/recreate_maker_swap_taker_saved.json b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_taker_saved.json new file mode 100644 index 0000000000..2d4e7dae34 --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_maker_swap_taker_saved.json @@ -0,0 +1,66 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "events":[ + {"timestamp":1638984440546,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "taker_payment_lock":1638992240, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_payment_wait":1638987560, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "fee_to_send_taker_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":false}, + "taker_payment_trade_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":false}, + "maker_payment_spend_trade_fee":{"coin":"RICK","amount":"0.00001","paid_from_trading_vol":true}}}}, + {"timestamp":1638984456603,"event":{"type":"Negotiated", + "data":{ + "maker_payment_locktime":1639000040, + "maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984456814,"event":{"type":"TakerFeeSent", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457822,"event":{"type":"MakerPaymentReceived", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984457826,"event":{"type":"MakerPaymentWaitConfirmStarted"}}, + {"timestamp":1638984503611,"event":{"type":"MakerPaymentValidatedAndConfirmed"}}, + {"timestamp":1638984503974,"event":{"type":"TakerPaymentSent", + "data":{ + "tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000", + "tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}}, + {"timestamp":1638984600390,"event":{"type":"TakerPaymentSpent", + "data":{ + "transaction":{ + "tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000", + "tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"}, + "secret":"23a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4"}}}, + {"timestamp":1638984600829,"event":{"type":"MakerPaymentSpent", + "data":{ + "tx_hex":"0400008085202f89013d20d0bf4318dfd61fe6b2fe5fe796759f40e5b17e83fb9b85cd5109d3e0876200000000d747304402200a57f752b760a8dcb932244dde0a46112a4d08bd5d31704c9138dc52b02a57e602204f0406dd354271e9850862e2e8c1feec57380e858952ab6cfedc8e7725196c94012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b6304e827b161b175210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b882103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac68ffffffff01ba256b05000000001976a91483762a373935ca241d557dfce89171d582b486de88ace827b161000000000000000000000000000000", + "tx_hash":"ca0721b69657c0ea2dcb848cc9e44e66d719ae10477097bf0fec57866a4f66aa"}}}, + {"timestamp":1638984600832,"event":{"type":"Finished"}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":"atomicDEX 0.5.1 iOS", + "mm_version":"1b065636a", + "success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"] +} \ No newline at end of file diff --git a/mm2src/mm2_main/src/for_tests/recreate_taker_swap_maker_saved.json b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_maker_saved.json new file mode 100644 index 0000000000..fe6d31561a --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_maker_saved.json @@ -0,0 +1,67 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"15d007fa-9237-489c-82a7-df061deba95f", + "events":[ + {"timestamp":1638984440198,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "secret":"0000000000000000000000000000000000000000000000000000000000000000", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "maker_payment_lock":1639000040, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "maker_payment_trade_fee":{ + "coin":"RICK", + "amount":"0.00001", + "paid_from_trading_vol":false}, + "taker_payment_spend_trade_fee":{ + "coin":"MORTY", + "amount":"0.00001", + "paid_from_trading_vol":true}}}}, + {"timestamp":1638984456204,"event":{"type":"Negotiated", + "data":{"taker_payment_locktime":1638992240, + "taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "maker_coin_swap_contract_addr":null, + "taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984457215,"event":{"type":"TakerFeeValidated", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457230,"event":{"type":"MakerPaymentSent", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984504262,"event":{"type":"TakerPaymentReceived", + "data":{ + "tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000", + "tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}}, + {"timestamp":1638984504263,"event":{"type":"TakerPaymentWaitConfirmStarted"}}, + {"timestamp":1638984594319,"event":{"type":"TakerPaymentValidatedAndConfirmed"}}, + {"timestamp":1638984594337,"event":{"type":"TakerPaymentSpent", + "data":{ + "tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000", + "tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"}}}, + {"timestamp":1638984594338,"event":{"type":"TakerPaymentSpendConfirmStarted"}}, + {"timestamp":1638984699392,"event":{"type":"TakerPaymentSpendConfirmed"}}, + {"timestamp":1638984699393,"event":{"type":"Finished"}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":"mpm", + "mm_version":"213bfddd5", + "success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"] +} \ No newline at end of file diff --git a/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_expected.json b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_expected.json new file mode 100644 index 0000000000..8184a0abff --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_expected.json @@ -0,0 +1,62 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "events":[ + {"timestamp":1638984440198,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "taker_payment_lock":1638992240, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_payment_wait":1638987560, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "fee_to_send_taker_fee":null, + "taker_payment_trade_fee":null, + "maker_payment_spend_trade_fee":null}}}, + {"timestamp":1638984456204,"event":{"type":"Negotiated", + "data":{ + "maker_payment_locktime":1639000040, + "maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "maker_coin_swap_contract_addr":null, + "taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984457215,"event":{"type":"TakerFeeSent", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457230,"event":{"type":"MakerPaymentReceived", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984457230,"event":{"type":"MakerPaymentWaitConfirmStarted"}}, + {"timestamp":1638984504262,"event":{"type":"MakerPaymentValidatedAndConfirmed"}}, + {"timestamp":1638984504262,"event":{"type":"TakerPaymentSent", + "data":{ + "tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000", + "tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}}, + {"timestamp":1638984594337,"event":{"type":"TakerPaymentSpent", + "data":{ + "transaction":{ + "tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000", + "tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"}, + "secret":"23a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4"}}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":null, + "mm_version":"", + "success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"] +} \ No newline at end of file diff --git a/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_maker_saved.json b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_maker_saved.json new file mode 100644 index 0000000000..b264cf78df --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_maker_saved.json @@ -0,0 +1,66 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"15d007fa-9237-489c-82a7-df061deba95f", + "events":[{ + "timestamp":1638984440198,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "secret":"0000000000000000000000000000000000000000000000000000000000000000", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "maker_payment_lock":1639000040, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "maker_payment_trade_fee":{ + "coin":"RICK", + "amount":"0.00001", + "paid_from_trading_vol":false}, + "taker_payment_spend_trade_fee":{ + "coin":"MORTY", + "amount":"0.00001", + "paid_from_trading_vol":true}}}}, + {"timestamp":1638984456204,"event":{"type":"Negotiated", + "data":{ + "taker_payment_locktime":1638992240, + "taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984457215,"event":{"type":"TakerFeeValidated", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457230,"event":{"type":"MakerPaymentSent", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984504262,"event":{"type":"TakerPaymentReceived", + "data":{ + "tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000", + "tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}}, + {"timestamp":1638984504263,"event":{"type":"TakerPaymentWaitConfirmStarted"}}, + {"timestamp":1638984594319,"event":{"type":"TakerPaymentWaitConfirmFailed","data":{"error":"An error"}}}, + {"timestamp":1638984594338,"event":{"type":"MakerPaymentWaitRefundStarted","data":{"wait_until":1639003740}}}, + {"timestamp":1639003740392,"event":{"type":"MakerPaymentRefunded", + "data":{ + "tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000", + "tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}}, + {"timestamp":1639003740398,"event":{"type":"Finished"}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":"mpm", + "mm_version":"213bfddd5", + "success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"] +} \ No newline at end of file diff --git a/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_taker_expected.json b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_taker_expected.json new file mode 100644 index 0000000000..06062260e2 --- /dev/null +++ b/mm2src/mm2_main/src/for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_taker_expected.json @@ -0,0 +1,58 @@ +{ + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "events":[ + {"timestamp":1638984440198,"event":{"type":"Started", + "data":{ + "taker_coin":"MORTY", + "maker_coin":"RICK", + "maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd", + "lock_duration":7800, + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "taker_amount":"1", + "maker_payment_confirmations":1, + "maker_payment_requires_nota":false, + "taker_payment_confirmations":1, + "taker_payment_requires_nota":false, + "taker_payment_lock":1638992240, + "uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4", + "started_at":1638984440, + "maker_payment_wait":1638987560, + "maker_coin_start_block":1207822, + "taker_coin_start_block":1222573, + "fee_to_send_taker_fee":null, + "taker_payment_trade_fee":null, + "maker_payment_spend_trade_fee":null}}}, + {"timestamp":1638984456204,"event":{"type":"Negotiated", + "data":{ + "maker_payment_locktime":1639000040, + "maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732", + "secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b", + "maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}}, + {"timestamp":1638984457215,"event":{"type":"TakerFeeSent", + "data":{ + "tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000", + "tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}}, + {"timestamp":1638984457230,"event":{"type":"MakerPaymentReceived", + "data":{ + "tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000", + "tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}}, + {"timestamp":1638984457230,"event":{"type":"MakerPaymentWaitConfirmStarted"}}, + {"timestamp":1638984504262,"event":{"type":"MakerPaymentValidatedAndConfirmed"}}, + {"timestamp":1638984504262,"event":{"type":"TakerPaymentSent", + "data":{ + "tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000", + "tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}}, + {"timestamp":1638984594319,"event":{"type":"TakerPaymentWaitForSpendFailed", + "data":{"error":"Origin Maker error event: TakerPaymentWaitConfirmFailed(SwapError { error: \"An error\" })"}}}, + {"timestamp":1638984594319,"event":{"type":"TakerPaymentWaitRefundStarted","data":{"wait_until":1638995940}}}], + "maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091", + "maker_coin":"RICK", + "taker_amount":"1", + "taker_coin":"MORTY", + "gui":null, + "mm_version":"", + "success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"], + "error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"] +} \ No newline at end of file diff --git a/mm2src/mm2_main/src/lp_network.rs b/mm2src/mm2_main/src/lp_network.rs index 2493d7eae6..a9903c5aa0 100644 --- a/mm2src/mm2_main/src/lp_network.rs +++ b/mm2src/mm2_main/src/lp_network.rs @@ -155,6 +155,12 @@ async fn process_p2p_message( lp_swap::process_msg(ctx.clone(), split.next().unwrap_or_default(), &message.data).await; to_propagate = true; }, + Some(lp_swap::WATCHER_PREFIX) => { + if ctx.is_watcher() { + lp_swap::process_watcher_msg(ctx.clone(), &message.data).await; + } + to_propagate = true; + }, Some(lp_swap::TX_HELPER_PREFIX) => { if let Some(pair) = split.next() { if let Ok(Some(coin)) = lp_coinfind(&ctx, pair).await { diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index 8456b5e007..66883f01cf 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -71,8 +71,10 @@ use mm2_core::mm_ctx::{from_ctx, MmArc}; use mm2_err_handle::prelude::*; use mm2_libp2p::{decode_signed, encode_and_sign, pub_sub_topic, TopicPrefix}; use mm2_number::{BigDecimal, BigRational, MmNumber}; +use parking_lot::Mutex as PaMutex; use primitives::hash::{H160, H264}; use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; +use serde::Serialize; use serde_json::{self as json, Value as Json}; use std::collections::{HashMap, HashSet}; use std::num::NonZeroUsize; @@ -91,6 +93,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; #[path = "lp_swap/recreate_swap_data.rs"] mod recreate_swap_data; #[path = "lp_swap/saved_swap.rs"] mod saved_swap; #[path = "lp_swap/swap_lock.rs"] mod swap_lock; +#[path = "lp_swap/swap_watcher.rs"] mod swap_watcher; #[path = "lp_swap/taker_swap.rs"] mod taker_swap; #[path = "lp_swap/trade_preimage.rs"] mod trade_preimage; @@ -109,10 +112,11 @@ use pubkey_banning::BanReason; pub use pubkey_banning::{ban_pubkey_rpc, is_pubkey_banned, list_banned_pubkeys_rpc, unban_pubkeys_rpc}; pub use recreate_swap_data::recreate_swap_data; pub use saved_swap::{SavedSwap, SavedSwapError, SavedSwapIo, SavedSwapResult}; +pub use swap_watcher::{process_watcher_msg, watcher_topic, TakerSwapWatcherData, WATCHER_PREFIX}; use taker_swap::TakerSwapEvent; pub use taker_swap::{calc_max_taker_vol, check_balance_for_taker_swap, max_taker_vol, max_taker_vol_from_available, run_taker_swap, taker_swap_trade_preimage, RunTakerSwapInput, TakerSavedSwap, TakerSwap, - TakerSwapPreparedParams, TakerTradePreimage}; + TakerSwapData, TakerSwapPreparedParams, TakerTradePreimage}; pub use trade_preimage::trade_preimage_rpc; pub const SWAP_PREFIX: TopicPrefix = "swap"; @@ -158,10 +162,10 @@ impl SwapMsgStore { /// Spawns the loop that broadcasts message every `interval` seconds returning the AbortOnDropHandle /// to stop it -pub fn broadcast_swap_message_every( +pub fn broadcast_swap_message_every( ctx: MmArc, topic: String, - msg: SwapMsg, + msg: T, interval: f64, p2p_privkey: Option, ) -> AbortOnDropHandle { @@ -175,7 +179,7 @@ pub fn broadcast_swap_message_every( } /// Broadcast the swap message once -pub fn broadcast_swap_message(ctx: &MmArc, topic: String, msg: SwapMsg, p2p_privkey: &Option) { +pub fn broadcast_swap_message(ctx: &MmArc, topic: String, msg: T, p2p_privkey: &Option) { let (p2p_private, from) = match p2p_privkey { Some(keypair) => (keypair.private_bytes(), Some(keypair.libp2p_peer_id())), None => (ctx.secp256k1_key_pair().private().secret.take(), None), @@ -200,6 +204,7 @@ pub async fn process_msg(ctx: MmArc, topic: &str, msg: &[u8]) { Ok(u) => u, Err(_) => return, }; + let msg = match decode_signed::(msg) { Ok(m) => m, Err(swap_msg_err) => { @@ -366,6 +371,7 @@ struct SwapsContext { /// Very unpleasant consequences shutdown_rx: async_std_sync::Receiver<()>, swap_msgs: Mutex>, + taker_swap_watchers: PaMutex>, #[cfg(target_arch = "wasm32")] swap_db: ConstructibleDb, } @@ -393,6 +399,7 @@ impl SwapsContext { banned_pubkeys: Mutex::new(HashMap::new()), shutdown_rx, swap_msgs: Mutex::new(HashMap::new()), + taker_swap_watchers: PaMutex::new(HashSet::new()), #[cfg(target_arch = "wasm32")] swap_db: ConstructibleDb::new(ctx), }) diff --git a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs index ecb3cd8db9..036928b139 100644 --- a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs +++ b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs @@ -265,6 +265,7 @@ fn convert_taker_to_maker_events( | TakerSwapEvent::MakerPaymentSpent(_) | TakerSwapEvent::MakerPaymentSpendFailed(_) // We don't know the reason at the moment, so we rely on the errors handling above. + | TakerSwapEvent::WatcherMessageSent(_) | TakerSwapEvent::TakerPaymentWaitRefundStarted { .. } | TakerSwapEvent::TakerPaymentRefunded(_) | TakerSwapEvent::TakerPaymentRefundFailed(_) @@ -492,11 +493,10 @@ mod tests { #[test] fn test_recreate_maker_swap() { - let taker_saved_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","events":[{"timestamp":1638984440546,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"taker_payment_lock":1638992240,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_payment_wait":1638987560,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"fee_to_send_taker_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":false},"taker_payment_trade_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":false},"maker_payment_spend_trade_fee":{"coin":"RICK","amount":"0.00001","paid_from_trading_vol":true}}}},{"timestamp":1638984456603,"event":{"type":"Negotiated","data":{"maker_payment_locktime":1639000040,"maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984456814,"event":{"type":"TakerFeeSent","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457822,"event":{"type":"MakerPaymentReceived","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984457826,"event":{"type":"MakerPaymentWaitConfirmStarted"}},{"timestamp":1638984503611,"event":{"type":"MakerPaymentValidatedAndConfirmed"}},{"timestamp":1638984503974,"event":{"type":"TakerPaymentSent","data":{"tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000","tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}},{"timestamp":1638984600390,"event":{"type":"TakerPaymentSpent","data":{"transaction":{"tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000","tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"},"secret":"23a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4"}}},{"timestamp":1638984600829,"event":{"type":"MakerPaymentSpent","data":{"tx_hex":"0400008085202f89013d20d0bf4318dfd61fe6b2fe5fe796759f40e5b17e83fb9b85cd5109d3e0876200000000d747304402200a57f752b760a8dcb932244dde0a46112a4d08bd5d31704c9138dc52b02a57e602204f0406dd354271e9850862e2e8c1feec57380e858952ab6cfedc8e7725196c94012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b6304e827b161b175210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b882103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac68ffffffff01ba256b05000000001976a91483762a373935ca241d557dfce89171d582b486de88ace827b161000000000000000000000000000000","tx_hash":"ca0721b69657c0ea2dcb848cc9e44e66d719ae10477097bf0fec57866a4f66aa"}}},{"timestamp":1638984600832,"event":{"type":"Finished"}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":"atomicDEX 0.5.1 iOS","mm_version":"1b065636a","success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"]}"#; - let maker_expected_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","events":[{"timestamp":1638984440546,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","secret":"0000000000000000000000000000000000000000000000000000000000000000","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"maker_payment_lock":1639000040,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"maker_payment_trade_fee":null,"taker_payment_spend_trade_fee":null}}},{"timestamp":1638984456603,"event":{"type":"Negotiated","data":{"taker_payment_locktime":1638992240,"taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984457822,"event":{"type":"TakerFeeValidated","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457822,"event":{"type":"MakerPaymentSent","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984503974,"event":{"type":"TakerPaymentReceived","data":{"tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000","tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}},{"timestamp":1638984503974,"event":{"type":"TakerPaymentWaitConfirmStarted"}},{"timestamp":1638984600390,"event":{"type":"TakerPaymentValidatedAndConfirmed"}},{"timestamp":1638984600390,"event":{"type":"TakerPaymentSpent","data":{"tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000","tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"}}},{"timestamp":1638984600390,"event":{"type":"TakerPaymentSpendConfirmStarted"}},{"timestamp":1638984600390,"event":{"type":"TakerPaymentSpendConfirmed"}},{"timestamp":1638984600390,"event":{"type":"Finished"}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":null,"mm_version":"","success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"]}"#; - - let taker_saved_swap: TakerSavedSwap = json::from_str(taker_saved_json).unwrap(); - let maker_expected_swap: MakerSavedSwap = json::from_str(maker_expected_json).unwrap(); + let taker_saved_swap: TakerSavedSwap = + json::from_str(include_str!("../for_tests/recreate_maker_swap_taker_saved.json")).unwrap(); + let maker_expected_swap: MakerSavedSwap = + json::from_str(include_str!("../for_tests/recreate_maker_swap_maker_expected.json")).unwrap(); let ctx = MmCtxBuilder::default().into_mm_arc(); @@ -507,11 +507,14 @@ mod tests { #[test] fn test_recreate_maker_swap_maker_payment_wait_confirm_failed() { - let taker_saved_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","events":[{"timestamp":1638984440546,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"taker_payment_lock":1638992240,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_payment_wait":1638987560,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"fee_to_send_taker_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":false},"taker_payment_trade_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":false},"maker_payment_spend_trade_fee":{"coin":"RICK","amount":"0.00001","paid_from_trading_vol":true}}}},{"timestamp":1638984456603,"event":{"type":"Negotiated","data":{"maker_payment_locktime":1639000040,"maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984456814,"event":{"type":"TakerFeeSent","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457822,"event":{"type":"MakerPaymentReceived","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984457826,"event":{"type":"MakerPaymentWaitConfirmStarted"}},{"timestamp":1638984503611,"event":{"type":"MakerPaymentWaitConfirmFailed","data":{"error":"An error"}}},{"timestamp":1638984503615,"event":{"type":"Finished"}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":"atomicDEX 0.5.1 iOS","mm_version":"1b065636a","success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"]}"#; - let maker_expected_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","events":[{"timestamp":1638984440546,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","secret":"0000000000000000000000000000000000000000000000000000000000000000","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"maker_payment_lock":1639000040,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"maker_payment_trade_fee":null,"taker_payment_spend_trade_fee":null}}},{"timestamp":1638984456603,"event":{"type":"Negotiated","data":{"taker_payment_locktime":1638992240,"taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984457822,"event":{"type":"TakerFeeValidated","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457822,"event":{"type":"MakerPaymentSent","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984503611,"event":{"type":"TakerPaymentValidateFailed","data":{"error":"Origin Taker error event: MakerPaymentWaitConfirmFailed(SwapError { error: \"An error\" })"}}},{"timestamp":1638984503611,"event":{"type":"MakerPaymentWaitRefundStarted","data":{"wait_until":1639003740}}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":null,"mm_version":"","success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"]}"#; - - let taker_saved_swap: TakerSavedSwap = json::from_str(taker_saved_json).unwrap(); - let maker_expected_swap: MakerSavedSwap = json::from_str(maker_expected_json).unwrap(); + let taker_saved_swap: TakerSavedSwap = json::from_str(include_str!( + "../for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_taker_saved.json" + )) + .unwrap(); + let maker_expected_swap: MakerSavedSwap = json::from_str(include_str!( + "../for_tests/recreate_maker_swap_maker_payment_wait_confirm_failed_maker_expected.json" + )) + .unwrap(); let ctx = MmCtxBuilder::default().into_mm_arc(); @@ -527,11 +530,10 @@ mod tests { MockResult::Return(Ok(secret)) }); - let maker_saved_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"15d007fa-9237-489c-82a7-df061deba95f","events":[{"timestamp":1638984440198,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","secret":"0000000000000000000000000000000000000000000000000000000000000000","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"maker_payment_lock":1639000040,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"maker_payment_trade_fee":{"coin":"RICK","amount":"0.00001","paid_from_trading_vol":false},"taker_payment_spend_trade_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":true}}}},{"timestamp":1638984456204,"event":{"type":"Negotiated","data":{"taker_payment_locktime":1638992240,"taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984457215,"event":{"type":"TakerFeeValidated","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457230,"event":{"type":"MakerPaymentSent","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984504262,"event":{"type":"TakerPaymentReceived","data":{"tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000","tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}},{"timestamp":1638984504263,"event":{"type":"TakerPaymentWaitConfirmStarted"}},{"timestamp":1638984594319,"event":{"type":"TakerPaymentValidatedAndConfirmed"}},{"timestamp":1638984594337,"event":{"type":"TakerPaymentSpent","data":{"tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000","tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"}}},{"timestamp":1638984594338,"event":{"type":"TakerPaymentSpendConfirmStarted"}},{"timestamp":1638984699392,"event":{"type":"TakerPaymentSpendConfirmed"}},{"timestamp":1638984699393,"event":{"type":"Finished"}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":"mpm","mm_version":"213bfddd5","success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"]}"#; - let taker_expected_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","events":[{"timestamp":1638984440198,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"taker_payment_lock":1638992240,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_payment_wait":1638987560,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"fee_to_send_taker_fee":null,"taker_payment_trade_fee":null,"maker_payment_spend_trade_fee":null}}},{"timestamp":1638984456204,"event":{"type":"Negotiated","data":{"maker_payment_locktime":1639000040,"maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984457215,"event":{"type":"TakerFeeSent","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457230,"event":{"type":"MakerPaymentReceived","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984457230,"event":{"type":"MakerPaymentWaitConfirmStarted"}},{"timestamp":1638984504262,"event":{"type":"MakerPaymentValidatedAndConfirmed"}},{"timestamp":1638984504262,"event":{"type":"TakerPaymentSent","data":{"tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000","tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}},{"timestamp":1638984594337,"event":{"type":"TakerPaymentSpent","data":{"transaction":{"tx_hex":"0400008085202f8901a24584831da75c6565cd3b7dd4150afdfe2a3ee77081ee151f6ed3db45ea7d6600000000d74730440220422edb8ef5cd3991eb309c3a4fa5fe5d9ffe08d3d6b4b789c5587061d7993864022049cd082398f5a37a9e7411d56976e61bcce9162d0f5f1fb24e40bcf2f4ec0052012023a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4004c6b63047009b161b1752103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddac6782012088a9144da9e7080175e8e10842e0e161b33cd298cab30b88210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ac68ffffffff0118ddf505000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac7009b161000000000000000000000000000000","tx_hash":"ab1eb5b65a302370af2607e0b64b60fc04360de33a87799bca1dcf337344b616"},"secret":"23a6bb64bc0ab2cc14cb84277d8d25134b814e5f999c66e578c9bba3c5e2d3a4"}}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":null,"mm_version":"","success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"]}"#; - - let maker_saved_swap: MakerSavedSwap = json::from_str(maker_saved_json).unwrap(); - let taker_expected_swap: TakerSavedSwap = json::from_str(taker_expected_json).unwrap(); + let maker_saved_swap: MakerSavedSwap = + json::from_str(include_str!("../for_tests/recreate_taker_swap_maker_saved.json")).unwrap(); + let taker_expected_swap: TakerSavedSwap = + json::from_str(include_str!("../for_tests/recreate_taker_swap_taker_expected.json")).unwrap(); let ctx = MmCtxBuilder::default().into_mm_arc(); let coins_ctx = CoinsContext::from_ctx(&ctx).unwrap(); @@ -544,11 +546,14 @@ mod tests { #[test] fn test_recreate_taker_swap_taker_payment_wait_confirm_failed() { - let maker_saved_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"15d007fa-9237-489c-82a7-df061deba95f","events":[{"timestamp":1638984440198,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","taker":"b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","secret":"0000000000000000000000000000000000000000000000000000000000000000","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","my_persistent_pub":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"maker_payment_lock":1639000040,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"maker_payment_trade_fee":{"coin":"RICK","amount":"0.00001","paid_from_trading_vol":false},"taker_payment_spend_trade_fee":{"coin":"MORTY","amount":"0.00001","paid_from_trading_vol":true}}}},{"timestamp":1638984456204,"event":{"type":"Negotiated","data":{"taker_payment_locktime":1638992240,"taker_pubkey":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984457215,"event":{"type":"TakerFeeValidated","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457230,"event":{"type":"MakerPaymentSent","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984504262,"event":{"type":"TakerPaymentReceived","data":{"tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000","tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}},{"timestamp":1638984504263,"event":{"type":"TakerPaymentWaitConfirmStarted"}},{"timestamp":1638984594319,"event":{"type":"TakerPaymentWaitConfirmFailed","data":{"error":"An error"}}},{"timestamp":1638984594338,"event":{"type":"MakerPaymentWaitRefundStarted","data":{"wait_until":1639003740}}},{"timestamp":1639003740392,"event":{"type":"MakerPaymentRefunded","data":{"tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000","tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}},{"timestamp":1639003740398,"event":{"type":"Finished"}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":"mpm","mm_version":"213bfddd5","success_events":["Started","Negotiated","TakerFeeValidated","MakerPaymentSent","TakerPaymentReceived","TakerPaymentWaitConfirmStarted","TakerPaymentValidatedAndConfirmed","TakerPaymentSpent","TakerPaymentSpendConfirmStarted","TakerPaymentSpendConfirmed","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeValidateFailed","MakerPaymentTransactionFailed","MakerPaymentDataSendFailed","MakerPaymentWaitConfirmFailed","TakerPaymentValidateFailed","TakerPaymentWaitConfirmFailed","TakerPaymentSpendFailed","TakerPaymentSpendConfirmFailed","MakerPaymentWaitRefundStarted","MakerPaymentRefunded","MakerPaymentRefundFailed"]}"#; - let taker_expected_json = r#"{"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","my_order_uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","events":[{"timestamp":1638984440198,"event":{"type":"Started","data":{"taker_coin":"MORTY","maker_coin":"RICK","maker":"15d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","my_persistent_pub":"03b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58addd","lock_duration":7800,"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","taker_amount":"1","maker_payment_confirmations":1,"maker_payment_requires_nota":false,"taker_payment_confirmations":1,"taker_payment_requires_nota":false,"taker_payment_lock":1638992240,"uuid":"f87fa9ce-0820-4675-b85d-db18c7bc9fb4","started_at":1638984440,"maker_payment_wait":1638987560,"maker_coin_start_block":1207822,"taker_coin_start_block":1222573,"fee_to_send_taker_fee":null,"taker_payment_trade_fee":null,"maker_payment_spend_trade_fee":null}}},{"timestamp":1638984456204,"event":{"type":"Negotiated","data":{"maker_payment_locktime":1639000040,"maker_pubkey":"0315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732","secret_hash":"4da9e7080175e8e10842e0e161b33cd298cab30b","maker_coin_swap_contract_addr":null,"taker_coin_swap_contract_addr":null}}},{"timestamp":1638984457215,"event":{"type":"TakerFeeSent","data":{"tx_hex":"0400008085202f89016383e8aced2256378bb126a1ca1a41e2f344d9295f65b3ea4b99055c5eb4a6cb000000006a47304402201c7e661e0dbeb9b3eb6e4e9e3194010e5772227017772b2e48c1b8d48ed3b21f02201c2eda64e74455fa1878a5c221f25d22fe626abd0078a26a9fc0f829e0921639012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff02bcf60100000000001976a914ca1e04745e8ca0c60d8c5881531d51bec470743f88ac74c3e90b000000001976a91483762a373935ca241d557dfce89171d582b486de88ac08ebb061000000000000000000000000000000","tx_hash":"fcb49167c79e8e014143643b94878866f7e80b26c5a5dcf693010543da70b5bc"}}},{"timestamp":1638984457230,"event":{"type":"MakerPaymentReceived","data":{"tx_hex":"0400008085202f8901c41fdf6b9d8aea4b472f83e4fa0d99dfafc245e897d681fd2ca7df30707fbf48020000006b483045022100c7b294bd46cbf3b13530879a43c5cf67414047266d8b64c3c7263b5e75b989ba02201974f38d688b184bc44e628806c6ab2ac9092f394729d0ce838f14e1e76117c001210315d9c51c657ab1be4ae9d3ab6e76a619d3bccfe830d5363fa168424c0d044732ffffffff03a2296b050000000017a91491c45f69e1760c12a1f90fb2a811f6dfde35cc35870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30bac503d64000000001976a9141462c3dd3f936d595c9af55978003b27c250441f88ac09ebb061000000000000000000000000000000","tx_hash":"6287e0d30951cd859bfb837eb1e5409f7596e75ffeb2e61fd6df1843bfd0203d"}}},{"timestamp":1638984457230,"event":{"type":"MakerPaymentWaitConfirmStarted"}},{"timestamp":1638984504262,"event":{"type":"MakerPaymentValidatedAndConfirmed"}},{"timestamp":1638984504262,"event":{"type":"TakerPaymentSent","data":{"tx_hex":"0400008085202f8901bcb570da43050193f6dca5c5260be8f7668887943b644341018e9ec76791b4fc010000006b483045022100fe6c90568a256b531bcd18321c15b3ce68c2d5d603768dea6aba68dcc170b801022076a34c006a92786bcdee6a1dcb46947fb49911e4f51ec27e880c3396d64d59b2012103b1e544ce2d860219bc91314b5483421a553a7b33044659eff0be9214ed58adddffffffff0300e1f5050000000017a9145a6125d597d2ce37bde9983d4d9d481335139bc4870000000000000000166a144da9e7080175e8e10842e0e161b33cd298cab30b8cdef305000000001976a91483762a373935ca241d557dfce89171d582b486de88ac37ebb061000000000000000000000000000000","tx_hash":"667dea45dbd36e1f15ee8170e73e2afefd0a15d47d3bcd65655ca71d838445a2"}}},{"timestamp":1638984594319,"event":{"type":"TakerPaymentWaitForSpendFailed","data":{"error":"Origin Maker error event: TakerPaymentWaitConfirmFailed(SwapError { error: \"An error\" })"}}},{"timestamp":1638984594319,"event":{"type":"TakerPaymentWaitRefundStarted","data":{"wait_until":1638995940}}}],"maker_amount":"0.9090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909091","maker_coin":"RICK","taker_amount":"1","taker_coin":"MORTY","gui":null,"mm_version":"","success_events":["Started","Negotiated","TakerFeeSent","MakerPaymentReceived","MakerPaymentWaitConfirmStarted","MakerPaymentValidatedAndConfirmed","TakerPaymentSent","TakerPaymentSpent","MakerPaymentSpent","Finished"],"error_events":["StartFailed","NegotiateFailed","TakerFeeSendFailed","MakerPaymentValidateFailed","MakerPaymentWaitConfirmFailed","TakerPaymentTransactionFailed","TakerPaymentWaitConfirmFailed","TakerPaymentDataSendFailed","TakerPaymentWaitForSpendFailed","MakerPaymentSpendFailed","TakerPaymentWaitRefundStarted","TakerPaymentRefunded","TakerPaymentRefundFailed"]}"#; - - let maker_saved_swap: MakerSavedSwap = json::from_str(maker_saved_json).unwrap(); - let taker_expected_swap: TakerSavedSwap = json::from_str(taker_expected_json).unwrap(); + let maker_saved_swap: MakerSavedSwap = json::from_str(include_str!( + "../for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_maker_saved.json" + )) + .unwrap(); + let taker_expected_swap: TakerSavedSwap = json::from_str(include_str!( + "../for_tests/recreate_taker_swap_taker_payment_wait_confirm_failed_taker_expected.json" + )) + .unwrap(); let ctx = MmCtxBuilder::default().into_mm_arc(); let coins_ctx = CoinsContext::from_ctx(&ctx).unwrap(); diff --git a/mm2src/mm2_main/src/lp_swap/swap_watcher.rs b/mm2src/mm2_main/src/lp_swap/swap_watcher.rs new file mode 100644 index 0000000000..1d7325c92b --- /dev/null +++ b/mm2src/mm2_main/src/lp_swap/swap_watcher.rs @@ -0,0 +1,463 @@ +use super::{broadcast_p2p_tx_msg, lp_coinfind, tx_helper_topic, H256Json, SwapsContext, TransactionIdentifier, + WAIT_CONFIRM_INTERVAL}; +use coins::{MmCoinEnum, WatcherValidatePaymentInput}; +use common::executor::spawn; +use common::log; +use common::log::{error, info}; +use futures::compat::Future01CompatExt; +use futures::{select, FutureExt}; +use mm2_core::mm_ctx::MmArc; +use mm2_libp2p::{decode_signed, pub_sub_topic, TopicPrefix}; +use mm2_number::BigDecimal; +use parking_lot::Mutex as PaMutex; +use std::cmp::min; +use std::sync::Arc; +use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use uuid::Uuid; + +pub const WATCHER_PREFIX: TopicPrefix = "swpwtchr"; +const TAKER_SWAP_CONFIRMATIONS: u64 = 1; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum SwapWatcherMsg { + TakerSwapWatcherMsg(Box), +} + +pub struct Watcher { + uuid: Uuid, + ctx: MmArc, + taker_coin: MmCoinEnum, + maker_coin: MmCoinEnum, + mutable: RwLock, + errors: PaMutex>, + data: TakerSwapWatcherData, +} + +pub struct WatcherMut { + taker_payment_spend: Option, + maker_payment_spend: Option, + secret: H256Json, +} + +#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] +pub struct TakerSwapWatcherData { + pub uuid: Uuid, + pub secret_hash: Vec, + pub taker_spends_maker_payment_preimage: Vec, + pub swap_started_at: u64, + pub lock_duration: u64, + pub taker_coin: String, + pub taker_payment_hex: Vec, + pub taker_payment_lock: u64, + pub taker_pub: Vec, + pub taker_coin_start_block: u64, + pub taker_payment_confirmations: u64, + pub taker_payment_requires_nota: Option, + pub taker_amount: BigDecimal, + pub maker_coin: String, + pub maker_pub: Vec, +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct TakerPaymentSpentData { + pub transaction: TransactionIdentifier, + pub secret: H256Json, +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +pub struct WatcherError { + error: String, +} + +impl From for WatcherError { + fn from(error: String) -> Self { WatcherError { error } } +} + +impl From<&str> for WatcherError { + fn from(e: &str) -> Self { WatcherError { error: e.to_owned() } } +} + +#[allow(clippy::large_enum_variant)] +pub enum RunWatcherInput { + StartNew(Watcher), +} + +impl RunWatcherInput { + fn uuid(&self) -> &Uuid { + match self { + RunWatcherInput::StartNew(swap) => &swap.uuid, + } + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(tag = "type", content = "data")] +#[allow(clippy::large_enum_variant)] +pub enum WatcherEvent { + Started, + StartFailed(WatcherError), + TakerPaymentWaitConfirmFailed(WatcherError), + TakerPaymentValidatedAndConfirmed, + TakerPaymentValidateFailed(WatcherError), + TakerPaymentSpent(TakerPaymentSpentData), + TakerPaymentWaitForSpendFailed(WatcherError), + MakerPaymentSpendFailed(WatcherError), + MakerPaymentSpent(TransactionIdentifier), + Finished, +} + +impl WatcherEvent { + pub fn status_str(&self) -> String { + match self { + WatcherEvent::Started => "Started...".to_owned(), + WatcherEvent::StartFailed(_) => "Start failed...".to_owned(), + WatcherEvent::TakerPaymentWaitConfirmFailed(_) => { + "Taker payment wait for confirmation failed...".to_owned() + }, + WatcherEvent::TakerPaymentValidatedAndConfirmed => "Taker payment validated and confirmed...".to_owned(), + WatcherEvent::TakerPaymentValidateFailed(_) => "Taker payment validate failed...".to_owned(), + WatcherEvent::TakerPaymentSpent(_) => "Taker payment spent...".to_owned(), + WatcherEvent::TakerPaymentWaitForSpendFailed(_) => "Taker payment wait for spend failed...".to_owned(), + WatcherEvent::MakerPaymentSpendFailed(_) => "Maker payment spend failed...".to_owned(), + WatcherEvent::MakerPaymentSpent(_) => "Maker payment spent...".to_owned(), + WatcherEvent::Finished => "Finished".to_owned(), + } + } +} + +#[derive(Debug)] +pub enum WatcherCommand { + Start, + ValidateTakerPayment, + WaitForTakerPaymentSpend, + SpendMakerPayment, + Finish, +} + +impl Watcher { + #[inline] + fn w(&self) -> RwLockWriteGuard { self.mutable.write().unwrap() } + + #[inline] + fn r(&self) -> RwLockReadGuard { self.mutable.read().unwrap() } + + #[inline] + fn apply_event(&self, event: WatcherEvent) { + match event { + WatcherEvent::Started => (), + WatcherEvent::StartFailed(err) => self.errors.lock().push(err), + WatcherEvent::TakerPaymentWaitConfirmFailed(err) => self.errors.lock().push(err), + WatcherEvent::TakerPaymentValidatedAndConfirmed => (), + WatcherEvent::TakerPaymentValidateFailed(err) => self.errors.lock().push(err), + WatcherEvent::TakerPaymentSpent(data) => { + self.w().taker_payment_spend = Some(data.transaction); + self.w().secret = data.secret; + }, + WatcherEvent::TakerPaymentWaitForSpendFailed(err) => self.errors.lock().push(err), + WatcherEvent::MakerPaymentSpendFailed(err) => self.errors.lock().push(err), + WatcherEvent::MakerPaymentSpent(tx) => self.w().maker_payment_spend = Some(tx), + WatcherEvent::Finished => (), + } + } + + async fn handle_command( + &self, + command: WatcherCommand, + ) -> Result<(Option, Vec), String> { + match command { + WatcherCommand::Start => self.start().await, + WatcherCommand::ValidateTakerPayment => self.validate_taker_payment().await, + WatcherCommand::WaitForTakerPaymentSpend => self.wait_for_taker_payment_spend().await, + WatcherCommand::SpendMakerPayment => self.spend_maker_payment().await, + WatcherCommand::Finish => Ok((None, vec![WatcherEvent::Finished])), + } + } + + pub fn new( + uuid: Uuid, + ctx: MmArc, + maker_coin: MmCoinEnum, + taker_coin: MmCoinEnum, + data: TakerSwapWatcherData, + ) -> Self { + Watcher { + uuid, + ctx, + maker_coin, + taker_coin, + errors: PaMutex::new(Vec::new()), + mutable: RwLock::new(WatcherMut { + taker_payment_spend: None, + maker_payment_spend: None, + secret: H256Json::default(), + }), + data, + } + } + + async fn start(&self) -> Result<(Option, Vec), String> { + Ok((Some(WatcherCommand::ValidateTakerPayment), vec![WatcherEvent::Started])) + } + + // Do we need the exact same validation as the maker, or should we use a simpler validation process? + async fn validate_taker_payment(&self) -> Result<(Option, Vec), String> { + let wait_duration = (self.data.lock_duration * 4) / 5; + let wait_taker_payment = self.data.swap_started_at + wait_duration; + let confirmations = min(self.data.taker_payment_confirmations, TAKER_SWAP_CONFIRMATIONS); + + // Does the watcher have to wait for the confirmations like the maker does? + let wait_f = self + .taker_coin + .wait_for_confirmations( + &self.data.taker_payment_hex, + confirmations, + self.data.taker_payment_requires_nota.unwrap_or(false), + wait_taker_payment, + WAIT_CONFIRM_INTERVAL, + ) + .compat(); + if let Err(err) = wait_f.await { + return Ok((Some(WatcherCommand::Finish), vec![ + WatcherEvent::TakerPaymentWaitConfirmFailed( + ERRL!("!taker_coin.wait_for_confirmations: {}", err).into(), + ), + ])); + } + + let validate_input = WatcherValidatePaymentInput { + payment_tx: self.data.taker_payment_hex.clone(), + time_lock: self.data.taker_payment_lock as u32, + taker_pub: self.data.taker_pub.clone(), + maker_pub: self.data.maker_pub.clone(), + secret_hash: self.data.secret_hash.clone(), + amount: self.data.taker_amount.clone(), + try_spv_proof_until: wait_taker_payment, + confirmations, + }; + + let validated_f = self.taker_coin.watcher_validate_taker_payment(validate_input).compat(); + + if let Err(e) = validated_f.await { + return Ok((Some(WatcherCommand::Finish), vec![ + WatcherEvent::TakerPaymentValidateFailed( + ERRL!("!taker_coin.watcher_validate_taker_payment: {}", e).into(), + ), + ])); + } + + Ok((Some(WatcherCommand::WaitForTakerPaymentSpend), vec![ + WatcherEvent::TakerPaymentValidatedAndConfirmed, + ])) + } + + async fn wait_for_taker_payment_spend(&self) -> Result<(Option, Vec), String> { + let f = self.taker_coin.wait_for_tx_spend( + &self.data.taker_payment_hex[..], + self.data.taker_payment_lock, + self.data.taker_coin_start_block, + &None, + ); + + let tx = match f.compat().await { + Ok(t) => t, + Err(err) => { + return Ok((Some(WatcherCommand::Finish), vec![ + WatcherEvent::TakerPaymentWaitForSpendFailed(err.get_plain_text_format().into()), + ])); + }, + }; + + let tx_hash = tx.tx_hash(); + info!("Taker payment spend tx {:02x}", tx_hash); + let tx_ident = TransactionIdentifier { + tx_hex: tx.tx_hex().into(), + tx_hash, + }; + + let secret = match self + .taker_coin + .extract_secret(&self.data.secret_hash[..], &tx_ident.tx_hex.0) + { + Ok(bytes) => H256Json::from(bytes.as_slice()), + Err(e) => { + return Ok((Some(WatcherCommand::Finish), vec![ + WatcherEvent::TakerPaymentWaitForSpendFailed(ERRL!("{}", e).into()), + ])); + }, + }; + + Ok((Some(WatcherCommand::SpendMakerPayment), vec![ + WatcherEvent::TakerPaymentSpent(TakerPaymentSpentData { + transaction: tx_ident, + secret, + }), + ])) + } + + async fn spend_maker_payment(&self) -> Result<(Option, Vec), String> { + let spend_fut = self.maker_coin.send_taker_spends_maker_payment_preimage( + &self.data.taker_spends_maker_payment_preimage, + &self.r().secret.0.clone(), + ); + + let transaction = match spend_fut.compat().await { + Ok(t) => t, + Err(err) => { + if let Some(tx) = err.get_tx() { + broadcast_p2p_tx_msg(&self.ctx, tx_helper_topic(self.maker_coin.ticker()), &tx, &None); + }; + + return Ok((Some(WatcherCommand::Finish), vec![ + WatcherEvent::MakerPaymentSpendFailed(ERRL!("{}", err.get_plain_text_format()).into()), + ])); + }, + }; + + broadcast_p2p_tx_msg( + &self.ctx, + tx_helper_topic(self.maker_coin.ticker()), + &transaction, + &None, + ); + + let tx_hash = transaction.tx_hash(); + info!("Maker payment spend tx {:02x}", tx_hash); + let tx_ident = TransactionIdentifier { + tx_hex: transaction.tx_hex().into(), + tx_hash, + }; + + Ok((Some(WatcherCommand::Finish), vec![WatcherEvent::MakerPaymentSpent( + tx_ident, + )])) + } +} + +pub async fn run_watcher(swap: RunWatcherInput, ctx: MmArc) { + let swap_ctx = SwapsContext::from_ctx(&ctx).unwrap(); + let uuid = swap.uuid().to_owned(); + + let (swap, mut command) = match swap { + RunWatcherInput::StartNew(swap) => (swap, WatcherCommand::Start), + }; + + let ctx = swap.ctx.clone(); + let mut status = ctx.log.status_handle(); + let uuid_str = swap.uuid.to_string(); + let running_swap = Arc::new(swap); + let shutdown_rx = swap_ctx.shutdown_rx.clone(); + let swap_for_log = running_swap.clone(); + + let mut swap_fut = Box::pin( + async move { + let mut events; + loop { + let res = running_swap.handle_command(command).await.expect("!handle_command"); + events = res.1; + for event in events { + status.status(&[&"swap", &("uuid", uuid_str.as_str())], &event.status_str()); + running_swap.apply_event(event); + } + match res.0 { + Some(c) => { + command = c; + }, + None => { + break; + }, + } + } + } + .fuse(), + ); + let mut shutdown_fut = Box::pin(shutdown_rx.recv().fuse()); + let do_nothing = (); // to fix https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit + select! { + _swap = swap_fut => { + swap_ctx.taker_swap_watchers.lock().remove(&uuid); + do_nothing + }, // swap finished normally + _shutdown = shutdown_fut => { + swap_ctx.taker_swap_watchers.lock().remove(&uuid); + info!("swap {} stopped!", swap_for_log.uuid) + }, + }; +} + +pub async fn process_watcher_msg(ctx: MmArc, msg: &[u8]) { + let msg = match decode_signed::(msg) { + Ok(m) => m, + Err(watcher_msg_err) => { + error!("Couldn't deserialize 'SwapWatcherMsg': {:?}", watcher_msg_err); + // Drop it to avoid dead_code warning + drop(watcher_msg_err); + return; + }, + }; + + match msg.0 { + SwapWatcherMsg::TakerSwapWatcherMsg(watcher_data) => spawn_taker_swap_watcher(ctx, *watcher_data), + } +} + +fn spawn_taker_swap_watcher(ctx: MmArc, watcher_data: TakerSwapWatcherData) { + let swap_ctx = SwapsContext::from_ctx(&ctx).unwrap(); + if swap_ctx.swap_msgs.lock().unwrap().contains_key(&watcher_data.uuid) { + return; + } + let mut taker_swap_watchers = swap_ctx.taker_swap_watchers.lock(); + if taker_swap_watchers.contains(&watcher_data.uuid) { + return; + } + taker_swap_watchers.insert(watcher_data.uuid); + drop(taker_swap_watchers); + + spawn(async move { + let taker_coin = match lp_coinfind(&ctx, &watcher_data.taker_coin).await { + Ok(Some(c)) => c, + Ok(None) => { + log::error!("Coin {} is not found/enabled", watcher_data.taker_coin); + let swap_ctx = SwapsContext::from_ctx(&ctx).unwrap(); + swap_ctx.taker_swap_watchers.lock().remove(&watcher_data.uuid); + return; + }, + Err(e) => { + log::error!("!lp_coinfind({}): {}", watcher_data.taker_coin, e); + let swap_ctx = SwapsContext::from_ctx(&ctx).unwrap(); + swap_ctx.taker_swap_watchers.lock().remove(&watcher_data.uuid); + return; + }, + }; + + let maker_coin = match lp_coinfind(&ctx, &watcher_data.maker_coin).await { + Ok(Some(c)) => c, + Ok(None) => { + log::error!("Coin {} is not found/enabled", watcher_data.maker_coin); + let swap_ctx = SwapsContext::from_ctx(&ctx).unwrap(); + swap_ctx.taker_swap_watchers.lock().remove(&watcher_data.uuid); + return; + }, + Err(e) => { + log::error!("!lp_coinfind({}): {}", watcher_data.maker_coin, e); + let swap_ctx = SwapsContext::from_ctx(&ctx).unwrap(); + swap_ctx.taker_swap_watchers.lock().remove(&watcher_data.uuid); + return; + }, + }; + + let uuid = watcher_data.uuid; + log_tag!( + ctx, + ""; + fmt = "Entering the watcher_swap_loop {}/{} with uuid: {}", + maker_coin.ticker(), + taker_coin.ticker(), + uuid + ); + + let watcher = Watcher::new(watcher_data.uuid, ctx.clone(), maker_coin, taker_coin, watcher_data); + run_watcher(RunWatcherInput::StartNew(watcher), ctx).await + }); +} + +pub fn watcher_topic(ticker: &str) -> String { pub_sub_topic(WATCHER_PREFIX, ticker) } diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 48e4a55a4c..569b8c9ee9 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -2,16 +2,18 @@ use super::check_balance::{check_my_coin_balance_for_swap, CheckBalanceError, Ch TakerFeeAdditionalInfo}; use super::pubkey_banning::ban_pubkey_on_failed_swap; use super::swap_lock::{SwapLock, SwapLockOps}; +use super::swap_watcher::{watcher_topic, SwapWatcherMsg}; use super::trade_preimage::{TradePreimageRequest, TradePreimageRpcError, TradePreimageRpcResult}; -use super::{broadcast_my_swap_status, broadcast_swap_message_every, check_other_coin_balance_for_swap, - dex_fee_amount_from_taker_coin, dex_fee_rate, dex_fee_threshold, get_locked_amount, recv_swap_msg, - swap_topic, AtomicSwap, LockedAmount, MySwapInfo, NegotiationDataMsg, NegotiationDataV2, - NegotiationDataV3, RecoveredSwap, RecoveredSwapAction, SavedSwap, SavedSwapIo, SavedTradeFee, - SwapConfirmationsSettings, SwapError, SwapMsg, SwapsContext, TransactionIdentifier, WAIT_CONFIRM_INTERVAL}; +use super::{broadcast_my_swap_status, broadcast_swap_message, broadcast_swap_message_every, + check_other_coin_balance_for_swap, dex_fee_amount_from_taker_coin, dex_fee_rate, dex_fee_threshold, + get_locked_amount, recv_swap_msg, swap_topic, AtomicSwap, LockedAmount, MySwapInfo, NegotiationDataMsg, + NegotiationDataV2, NegotiationDataV3, RecoveredSwap, RecoveredSwapAction, SavedSwap, SavedSwapIo, + SavedTradeFee, SwapConfirmationsSettings, SwapError, SwapMsg, SwapsContext, TransactionIdentifier, + WAIT_CONFIRM_INTERVAL}; use crate::mm2::lp_network::subscribe_to_topic; use crate::mm2::lp_ordermatch::{MatchBy, OrderConfirmationsSettings, TakerAction, TakerOrderBuilder}; use crate::mm2::lp_price::fetch_swap_coins_price; -use crate::mm2::lp_swap::{broadcast_p2p_tx_msg, tx_helper_topic}; +use crate::mm2::lp_swap::{broadcast_p2p_tx_msg, tx_helper_topic, TakerSwapWatcherData}; use crate::mm2::MM_VERSION; use coins::{lp_coinfind, CanRefundHtlc, FeeApproxStage, FoundSwapTxSpend, MmCoinEnum, SearchForSwapTxSpendInput, TradeFee, TradePreimageValue, ValidatePaymentInput}; @@ -47,6 +49,20 @@ pub const TAKER_SUCCESS_EVENTS: [&str; 10] = [ "Finished", ]; +pub const TAKER_USING_WATCHERS_SUCCESS_EVENTS: [&str; 11] = [ + "Started", + "Negotiated", + "TakerFeeSent", + "MakerPaymentReceived", + "MakerPaymentWaitConfirmStarted", + "MakerPaymentValidatedAndConfirmed", + "TakerPaymentSent", + "WatcherMessageSent", + "TakerPaymentSpent", + "MakerPaymentSpent", + "Finished", +]; + pub const TAKER_ERROR_EVENTS: [&str; 13] = [ "StartFailed", "NegotiateFailed", @@ -84,7 +100,13 @@ async fn save_my_taker_swap_event(ctx: &MmArc, swap: &TakerSwap, event: TakerSav gui: ctx.gui().map(|g| g.to_owned()), mm_version: Some(MM_VERSION.to_owned()), events: vec![], - success_events: TAKER_SUCCESS_EVENTS.iter().map(|event| event.to_string()).collect(), + success_events: match ctx.use_watchers() { + true => TAKER_USING_WATCHERS_SUCCESS_EVENTS + .iter() + .map(|event| event.to_string()) + .collect(), + false => TAKER_SUCCESS_EVENTS.iter().map(|event| event.to_string()).collect(), + }, error_events: TAKER_ERROR_EVENTS.iter().map(|event| event.to_string()).collect(), }), Err(e) => return ERR!("{}", e), @@ -125,6 +147,7 @@ impl TakerSavedEvent { TakerSwapEvent::MakerPaymentValidateFailed(_) => Some(TakerSwapCommand::Finish), TakerSwapEvent::MakerPaymentWaitConfirmFailed(_) => Some(TakerSwapCommand::Finish), TakerSwapEvent::TakerPaymentSent(_) => Some(TakerSwapCommand::WaitForTakerPaymentSpend), + TakerSwapEvent::WatcherMessageSent(_) => Some(TakerSwapCommand::WaitForTakerPaymentSpend), TakerSwapEvent::TakerPaymentTransactionFailed(_) => Some(TakerSwapCommand::Finish), TakerSwapEvent::TakerPaymentDataSendFailed(_) => Some(TakerSwapCommand::RefundTakerPayment), TakerSwapEvent::TakerPaymentSpent(_) => Some(TakerSwapCommand::SpendMakerPayment), @@ -464,6 +487,7 @@ pub struct TakerSwapMut { taker_payment: Option, maker_payment_spend: Option, taker_payment_spend: Option, + taker_spends_maker_payment_preimage: Option>, taker_payment_refund: Option, secret_hash: H160Json, secret: H256Json, @@ -550,6 +574,7 @@ pub enum TakerSwapEvent { MakerPaymentValidateFailed(SwapError), MakerPaymentWaitConfirmFailed(SwapError), TakerPaymentSent(TransactionIdentifier), + WatcherMessageSent(Option>), TakerPaymentTransactionFailed(SwapError), TakerPaymentDataSendFailed(SwapError), TakerPaymentWaitConfirmFailed(SwapError), @@ -580,6 +605,7 @@ impl TakerSwapEvent { "Maker payment wait for confirmation failed...".to_owned() }, TakerSwapEvent::TakerPaymentSent(_) => "Taker payment sent...".to_owned(), + TakerSwapEvent::WatcherMessageSent(_) => "Watcher message sent...".to_owned(), TakerSwapEvent::TakerPaymentTransactionFailed(_) => "Taker payment transaction failed...".to_owned(), TakerSwapEvent::TakerPaymentDataSendFailed(_) => "Taker payment data send failed...".to_owned(), TakerSwapEvent::TakerPaymentWaitConfirmFailed(_) => { @@ -613,6 +639,7 @@ impl TakerSwapEvent { | TakerSwapEvent::TakerFeeSent(_) | TakerSwapEvent::MakerPaymentReceived(_) | TakerSwapEvent::MakerPaymentWaitConfirmStarted + | TakerSwapEvent::WatcherMessageSent(_) | TakerSwapEvent::MakerPaymentValidatedAndConfirmed | TakerSwapEvent::TakerPaymentSent(_) | TakerSwapEvent::TakerPaymentSpent(_) @@ -696,6 +723,9 @@ impl TakerSwap { TakerSwapEvent::MakerPaymentValidateFailed(err) => self.errors.lock().push(err), TakerSwapEvent::MakerPaymentWaitConfirmFailed(err) => self.errors.lock().push(err), TakerSwapEvent::TakerPaymentSent(tx) => self.w().taker_payment = Some(tx), + TakerSwapEvent::WatcherMessageSent(preimage_hex) => { + self.w().taker_spends_maker_payment_preimage = preimage_hex + }, TakerSwapEvent::TakerPaymentTransactionFailed(err) => self.errors.lock().push(err), TakerSwapEvent::TakerPaymentDataSendFailed(err) => self.errors.lock().push(err), TakerSwapEvent::TakerPaymentWaitConfirmFailed(err) => self.errors.lock().push(err), @@ -770,6 +800,7 @@ impl TakerSwap { maker_payment: None, taker_payment: None, taker_payment_spend: None, + taker_spends_maker_payment_preimage: None, maker_payment_spend: None, taker_payment_refund: None, secret_hash: H160Json::default(), @@ -1178,6 +1209,30 @@ impl TakerSwap { ])) } + fn create_watcher_data( + &self, + taker_payment_hex: Vec, + taker_spends_maker_payment_preimage: Vec, + ) -> TakerSwapWatcherData { + TakerSwapWatcherData { + uuid: self.uuid, + secret_hash: self.r().secret_hash.into(), + taker_spends_maker_payment_preimage, + swap_started_at: self.r().data.started_at, + lock_duration: self.r().data.lock_duration, + taker_coin: self.r().data.taker_coin.clone(), + taker_payment_hex, + taker_payment_lock: self.r().data.taker_payment_lock, + taker_pub: self.r().data.taker_coin_htlc_pubkey.unwrap().into(), + taker_coin_start_block: self.r().data.taker_coin_start_block, + taker_payment_confirmations: self.r().data.taker_payment_confirmations, + taker_payment_requires_nota: self.r().data.taker_payment_requires_nota, + taker_amount: self.r().data.taker_amount.clone(), + maker_coin: self.r().data.maker_coin.clone(), + maker_pub: self.r().other_maker_coin_htlc_pub.to_vec(), + } + } + async fn send_taker_payment(&self) -> Result<(Option, Vec), String> { #[cfg(test)] if self.fail_at == Some(FailAt::TakerPayment) { @@ -1242,13 +1297,55 @@ impl TakerSwap { tx_hash, }; - Ok((Some(TakerSwapCommand::WaitForTakerPaymentSpend), vec![ - TakerSwapEvent::TakerPaymentSent(tx_ident), - ])) + let mut swap_events = vec![TakerSwapEvent::TakerPaymentSent(tx_ident)]; + if self.ctx.use_watchers() { + let preimage_fut = self.taker_coin.create_taker_spends_maker_payment_preimage( + &self.r().maker_payment.as_ref().unwrap().tx_hex, + self.maker_payment_lock.load(Ordering::Relaxed) as u32, + self.r().other_maker_coin_htlc_pub.as_slice(), + &self.r().secret_hash.0, + &self.unique_swap_data()[..], + ); + + match preimage_fut.compat().await { + Ok(preimage) => { + let watcher_data = self.create_watcher_data(transaction.tx_hex(), preimage.tx_hex()); + let swpmsg_watcher = SwapWatcherMsg::TakerSwapWatcherMsg(Box::new(watcher_data)); + broadcast_swap_message( + &self.ctx, + watcher_topic(&self.r().data.taker_coin), + swpmsg_watcher, + &self.p2p_privkey, + ); + swap_events.push(TakerSwapEvent::WatcherMessageSent(Some(preimage.tx_hex()))) + }, + Err(e) => error!( + "The watcher message could not be sent, error creating the taker spends maker payment preimage: {}", + e.get_plain_text_format() + ), + } + } + + Ok((Some(TakerSwapCommand::WaitForTakerPaymentSpend), swap_events)) } async fn wait_for_taker_payment_spend(&self) -> Result<(Option, Vec), String> { let tx_hex = self.r().taker_payment.as_ref().unwrap().tx_hex.0.clone(); + let mut watcher_broadcast_abort_handle = None; + if self.ctx.use_watchers() { + let preimage_hex = self.r().taker_spends_maker_payment_preimage.clone(); + if let Some(preimage_hex) = preimage_hex { + let watcher_data = self.create_watcher_data(tx_hex.clone(), preimage_hex); + let swpmsg_watcher = SwapWatcherMsg::TakerSwapWatcherMsg(Box::new(watcher_data)); + watcher_broadcast_abort_handle = Some(broadcast_swap_message_every( + self.ctx.clone(), + watcher_topic(&self.r().data.taker_coin), + swpmsg_watcher, + 600., + self.p2p_privkey, + )); + } + } let msg = SwapMsg::TakerPayment(tx_hex); let send_abort_handle = broadcast_swap_message_every(self.ctx.clone(), swap_topic(&self.uuid), msg, 600., self.p2p_privkey); @@ -1294,6 +1391,7 @@ impl TakerSwap { }, }; drop(send_abort_handle); + drop(watcher_broadcast_abort_handle); let tx_hash = tx.tx_hash(); info!("Taker payment spend tx {:02x}", tx_hash); let tx_ident = TransactionIdentifier { diff --git a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs index 158ca32a79..de8882a55d 100644 --- a/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs +++ b/mm2src/mm2_main/src/rpc/lp_commands/lp_commands_legacy.rs @@ -34,7 +34,7 @@ use std::borrow::Cow; use crate::mm2::lp_dispatcher::{dispatch_lp_event, StopCtxEvent}; use crate::mm2::lp_network::subscribe_to_topic; use crate::mm2::lp_ordermatch::{cancel_orders_by, CancelBy}; -use crate::mm2::lp_swap::{active_swaps_using_coin, tx_helper_topic}; +use crate::mm2::lp_swap::{active_swaps_using_coin, tx_helper_topic, watcher_topic}; use crate::mm2::MmVersionResult; /// Attempts to disable the coin @@ -141,6 +141,9 @@ pub async fn enable(ctx: MmArc, req: Json) -> Result>, String> if coin.is_utxo_in_native_mode() { subscribe_to_topic(&ctx, tx_helper_topic(coin.ticker())); } + if ctx.is_watcher() { + subscribe_to_topic(&ctx, watcher_topic(coin.ticker())); + } Ok(res) } diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 5b02543c20..a26aec48de 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -142,7 +142,38 @@ impl Mm2TestConf { } } + pub fn seednode_using_watchers(passphrase: &str, coins: &Json) -> Self { + Mm2TestConf { + conf: json!({ + "gui": "nogui", + "netid": 9998, + "passphrase": passphrase, + "coins": coins, + "rpc_password": DEFAULT_RPC_PASSWORD, + "i_am_seed": true, + "use_watchers": true, + }), + rpc_password: DEFAULT_RPC_PASSWORD.into(), + local: None, + } + } + pub fn light_node(passphrase: &str, coins: &Json, seednodes: &[&str]) -> Self { + Mm2TestConf { + conf: json!({ + "gui": "nogui", + "netid": 9998, + "passphrase": passphrase, + "coins": coins, + "rpc_password": DEFAULT_RPC_PASSWORD, + "seednodes": seednodes + }), + rpc_password: DEFAULT_RPC_PASSWORD.into(), + local: None, + } + } + + pub fn watcher_light_node(passphrase: &str, coins: &Json, seednodes: &[&str]) -> Self { Mm2TestConf { conf: json!({ "gui": "nogui", @@ -151,6 +182,7 @@ impl Mm2TestConf { "coins": coins, "rpc_password": DEFAULT_RPC_PASSWORD, "seednodes": seednodes, + "is_watcher": true }), rpc_password: DEFAULT_RPC_PASSWORD.into(), local: None,