From 13a798e5e470a245813f82d5ec33ae39514da2e6 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 24 Apr 2024 15:55:46 +0200 Subject: [PATCH 01/38] use u8 for forkid --- mm2src/coins/utxo.rs | 2 +- mm2src/coins/utxo/qtum.rs | 2 +- .../utxo/utxo_builder/utxo_conf_builder.rs | 18 +++--- mm2src/coins/utxo/utxo_common.rs | 10 ++-- mm2src/coins/utxo/utxo_standard.rs | 2 +- mm2src/coins/utxo_signer/src/lib.rs | 2 +- mm2src/coins/utxo_signer/src/sign_common.rs | 16 +++--- mm2src/coins/utxo_signer/src/with_key_pair.rs | 24 ++++---- mm2src/coins/utxo_signer/src/with_trezor.rs | 2 +- mm2src/mm2_bitcoin/script/src/sign.rs | 56 +++++++++---------- mm2src/mm2_bitcoin/script/src/verify.rs | 6 +- 11 files changed, 71 insertions(+), 69 deletions(-) diff --git a/mm2src/coins/utxo.rs b/mm2src/coins/utxo.rs index 6cf25fcf7f..4f1bd35b31 100644 --- a/mm2src/coins/utxo.rs +++ b/mm2src/coins/utxo.rs @@ -552,7 +552,7 @@ pub struct UtxoCoinConf { /// Address and privkey checksum type pub checksum_type: ChecksumType, /// Fork id used in sighash - pub fork_id: u32, + pub fork_id: u8, /// Signature version pub signature_version: SignatureVersion, pub required_confirmations: AtomicU64, diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 9d1b16723d..24789cc510 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -1032,7 +1032,7 @@ impl UtxoSignerOps for QtumCoin { }) } - fn fork_id(&self) -> u32 { self.utxo_arc.conf.fork_id } + fn fork_id(&self) -> u8 { self.utxo_arc.conf.fork_id } fn branch_id(&self) -> u32 { self.utxo_arc.conf.consensus_branch_id } diff --git a/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs index befbae70f9..4d4e9029d7 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs @@ -34,6 +34,8 @@ pub enum UtxoConfError { InvalidVersionGroupId(String), InvalidAddressFormat(String), InvalidDecimals(String), + #[display(fmt = "Invalid fork id: {}, valid fork ids are values between 0x00 - 0xff", _0)] + InvalidForkId(String), } impl From for UtxoConfError { @@ -91,8 +93,8 @@ impl<'a> UtxoConfBuilder<'a> { let tx_fee_volatility_percent = self.tx_fee_volatility_percent(); let version_group_id = self.version_group_id(tx_version, overwintered)?; let consensus_branch_id = self.consensus_branch_id(tx_version)?; - let signature_version = self.signature_version(); - let fork_id = self.fork_id(); + let signature_version = self.signature_version()?; + let fork_id = self.fork_id()?; // should be sufficient to detect zcash by overwintered flag let zcash = overwintered; @@ -244,23 +246,23 @@ impl<'a> UtxoConfBuilder<'a> { Ok(consensus_branch_id) } - fn signature_version(&self) -> SignatureVersion { - let default_signature_version = if self.ticker == "BCH" || self.fork_id() != 0 { + fn signature_version(&self) -> UtxoConfResult { + let default_signature_version = if self.ticker == "BCH" || self.fork_id()? != 0 { SignatureVersion::ForkId } else { SignatureVersion::Base }; - json::from_value(self.conf["signature_version"].clone()).unwrap_or(default_signature_version) + Ok(json::from_value(self.conf["signature_version"].clone()).unwrap_or(default_signature_version)) } - fn fork_id(&self) -> u32 { + fn fork_id(&self) -> UtxoConfResult { let default_fork_id = match self.ticker { "BCH" => "0x40", _ => "0x0", }; let hex_string = self.conf["fork_id"].as_str().unwrap_or(default_fork_id); - let fork_id = u32::from_str_radix(hex_string.trim_start_matches("0x"), 16).unwrap(); - fork_id + u8::from_str_radix(hex_string.trim_start_matches("0x"), 16) + .map_to_mm(|e| UtxoConfError::InvalidForkId(e.to_string())) } fn required_confirmations(&self) -> u64 { diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index c757e942db..e0dabb0a67 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -1181,13 +1181,13 @@ pub async fn sign_and_send_taker_funding_spend( SIGHASH_ALL, coin.as_ref().conf.fork_id )); - let sig_hash_all_fork_id = (SIGHASH_ALL | coin.as_ref().conf.fork_id) as u8; + let sig_hash_all_fork_id = SIGHASH_ALL | coin.as_ref().conf.fork_id; let mut maker_signature_with_sighash = preimage.signature.to_vec(); maker_signature_with_sighash.push(sig_hash_all_fork_id); drop_mutability!(maker_signature_with_sighash); - let mut taker_signature_with_sighash: Vec = taker_signature.take(); + let mut taker_signature_with_sighash = taker_signature.take(); taker_signature_with_sighash.push(sig_hash_all_fork_id); drop_mutability!(taker_signature_with_sighash); @@ -1427,14 +1427,14 @@ pub async fn sign_and_broadcast_taker_payment_spend( )); let mut taker_signature_with_sighash = preimage.signature.to_vec(); let taker_sig_hash = match gen_args.dex_fee { - DexFee::Standard(_) => (SIGHASH_SINGLE | coin.as_ref().conf.fork_id) as u8, - DexFee::WithBurn { .. } => (SIGHASH_ALL | coin.as_ref().conf.fork_id) as u8, + DexFee::Standard(_) => SIGHASH_SINGLE | coin.as_ref().conf.fork_id, + DexFee::WithBurn { .. } => SIGHASH_ALL | coin.as_ref().conf.fork_id, }; taker_signature_with_sighash.push(taker_sig_hash); drop_mutability!(taker_signature_with_sighash); - let sig_hash_all_fork_id = (SIGHASH_ALL | coin.as_ref().conf.fork_id) as u8; + let sig_hash_all_fork_id = SIGHASH_ALL | coin.as_ref().conf.fork_id; let mut maker_signature_with_sighash: Vec = maker_signature.take(); maker_signature_with_sighash.push(sig_hash_all_fork_id); drop_mutability!(maker_signature_with_sighash); diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 93c0535b74..7137d6679b 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -1045,7 +1045,7 @@ impl UtxoSignerOps for UtxoStandardCoin { }) } - fn fork_id(&self) -> u32 { self.utxo_arc.conf.fork_id } + fn fork_id(&self) -> u8 { self.utxo_arc.conf.fork_id } fn branch_id(&self) -> u32 { self.utxo_arc.conf.consensus_branch_id } diff --git a/mm2src/coins/utxo_signer/src/lib.rs b/mm2src/coins/utxo_signer/src/lib.rs index 9285bf8587..c94fe0dd0e 100644 --- a/mm2src/coins/utxo_signer/src/lib.rs +++ b/mm2src/coins/utxo_signer/src/lib.rs @@ -120,7 +120,7 @@ pub trait UtxoSignerOps { fn trezor_coin(&self) -> UtxoSignTxResult; - fn fork_id(&self) -> u32; + fn fork_id(&self) -> u8; fn branch_id(&self) -> u32; diff --git a/mm2src/coins/utxo_signer/src/sign_common.rs b/mm2src/coins/utxo_signer/src/sign_common.rs index 1ba966aa6b..f7e930a508 100644 --- a/mm2src/coins/utxo_signer/src/sign_common.rs +++ b/mm2src/coins/utxo_signer/src/sign_common.rs @@ -1,4 +1,4 @@ -use crate::Signature; +use crate::{with_key_pair::SIGHASH_ALL, Signature}; use chain::{Transaction as UtxoTx, TransactionInput}; use keys::bytes::Bytes; use keys::Public as PublicKey; @@ -32,7 +32,7 @@ pub(crate) fn complete_tx(unsigned: TransactionInputSigner, signed_inputs: Vec TransactionInput { let script_sig = script_sig(signature, fork_id); @@ -49,7 +49,7 @@ pub(crate) fn p2pk_spend_with_signature( pub(crate) fn p2pkh_spend_with_signature( unsigned_input: &UnsignedTransactionInput, public_key: &PublicKey, - fork_id: u32, + fork_id: u8, signature: Signature, ) -> TransactionInput { let script_sig = script_sig_with_pub(public_key, fork_id, signature); @@ -67,7 +67,7 @@ pub(crate) fn p2sh_spend_with_signature( unsigned_input: &UnsignedTransactionInput, redeem_script: Script, script_data: Script, - fork_id: u32, + fork_id: u8, signature: Signature, ) -> TransactionInput { let script_sig = script_sig(signature, fork_id); @@ -92,7 +92,7 @@ pub(crate) fn p2sh_spend_with_signature( pub(crate) fn p2wpkh_spend_with_signature( unsigned_input: &UnsignedTransactionInput, public_key: &PublicKey, - fork_id: u32, + fork_id: u8, signature: Signature, ) -> TransactionInput { let script_sig = script_sig(signature, fork_id); @@ -105,7 +105,7 @@ pub(crate) fn p2wpkh_spend_with_signature( } } -pub(crate) fn script_sig_with_pub(public_key: &PublicKey, fork_id: u32, signature: Signature) -> Bytes { +pub(crate) fn script_sig_with_pub(public_key: &PublicKey, fork_id: u8, signature: Signature) -> Bytes { let script_sig = script_sig(signature, fork_id); let builder = Builder::default(); builder @@ -114,12 +114,12 @@ pub(crate) fn script_sig_with_pub(public_key: &PublicKey, fork_id: u32, signatur .into_bytes() } -pub(crate) fn script_sig(mut signature: Signature, fork_id: u32) -> Bytes { +pub(crate) fn script_sig(mut signature: Signature, fork_id: u8) -> Bytes { let mut sig_script = Bytes::default(); sig_script.append(&mut signature); // Using SIGHASH_ALL only for now - sig_script.append(&mut Bytes::from(vec![1 | fork_id as u8])); + sig_script.append(&mut Bytes::from(vec![SIGHASH_ALL | fork_id])); sig_script } diff --git a/mm2src/coins/utxo_signer/src/with_key_pair.rs b/mm2src/coins/utxo_signer/src/with_key_pair.rs index 151884a05e..d0144836d1 100644 --- a/mm2src/coins/utxo_signer/src/with_key_pair.rs +++ b/mm2src/coins/utxo_signer/src/with_key_pair.rs @@ -9,9 +9,9 @@ use mm2_err_handle::prelude::*; use primitives::hash::H256; use script::{Builder, Script, SignatureVersion, TransactionInputSigner, UnsignedTransactionInput}; -pub const SIGHASH_ALL: u32 = 1; -pub const _SIGHASH_NONE: u32 = 2; -pub const SIGHASH_SINGLE: u32 = 3; +pub const SIGHASH_ALL: u8 = 1; +pub const _SIGHASH_NONE: u8 = 2; +pub const SIGHASH_SINGLE: u8 = 3; pub type UtxoSignWithKeyPairResult = Result>; @@ -43,7 +43,7 @@ pub fn sign_tx( key_pair: &KeyPair, prev_script: Script, signature_version: SignatureVersion, - fork_id: u32, + fork_id: u8, ) -> UtxoSignWithKeyPairResult { let mut signed_inputs = Vec::with_capacity(unsigned.inputs.len()); match signature_version { @@ -81,7 +81,7 @@ pub fn p2pk_spend( input_index: usize, key_pair: &KeyPair, signature_version: SignatureVersion, - fork_id: u32, + fork_id: u8, ) -> UtxoSignWithKeyPairResult { let unsigned_input = get_input(signer, input_index)?; @@ -105,7 +105,7 @@ pub fn p2pkh_spend( key_pair: &KeyPair, prev_script: Script, signature_version: SignatureVersion, - fork_id: u32, + fork_id: u8, ) -> UtxoSignWithKeyPairResult { let unsigned_input = get_input(signer, input_index)?; @@ -143,7 +143,7 @@ pub fn p2sh_spend( script_data: Script, redeem_script: Script, signature_version: SignatureVersion, - fork_id: u32, + fork_id: u8, ) -> UtxoSignWithKeyPairResult { let unsigned_input = get_input(signer, input_index)?; @@ -172,7 +172,7 @@ pub fn p2wpkh_spend( key_pair: &KeyPair, prev_script: Script, signature_version: SignatureVersion, - fork_id: u32, + fork_id: u8, ) -> UtxoSignWithKeyPairResult { let unsigned_input = get_input(signer, input_index)?; @@ -210,8 +210,8 @@ pub fn calc_and_sign_sighash( output_script: &Script, key_pair: &KeyPair, signature_version: SignatureVersion, - sighash_type: u32, - fork_id: u32, + sighash_type: u8, + fork_id: u8, ) -> UtxoSignWithKeyPairResult { let sighash = signature_hash_to_sign( signer, @@ -229,8 +229,8 @@ pub fn signature_hash_to_sign( input_index: usize, output_script: &Script, signature_version: SignatureVersion, - sighash_type: u32, - fork_id: u32, + sighash_type: u8, + fork_id: u8, ) -> UtxoSignWithKeyPairResult { let input_amount = get_input(signer, input_index)?.amount; diff --git a/mm2src/coins/utxo_signer/src/with_trezor.rs b/mm2src/coins/utxo_signer/src/with_trezor.rs index 8da3b972bb..a949dc0376 100644 --- a/mm2src/coins/utxo_signer/src/with_trezor.rs +++ b/mm2src/coins/utxo_signer/src/with_trezor.rs @@ -17,7 +17,7 @@ pub struct TrezorTxSigner<'a, TxP> { pub tx_provider: TxP, pub trezor_coin: String, pub params: UtxoSignTxParams, - pub fork_id: u32, + pub fork_id: u8, pub branch_id: u32, } diff --git a/mm2src/mm2_bitcoin/script/src/sign.rs b/mm2src/mm2_bitcoin/script/src/sign.rs index 58b3eea6fa..4185a9a756 100644 --- a/mm2src/mm2_bitcoin/script/src/sign.rs +++ b/mm2src/mm2_bitcoin/script/src/sign.rs @@ -37,8 +37,8 @@ pub enum SighashBase { Single = 3, } -impl From for u32 { - fn from(s: SighashBase) -> Self { s as u32 } +impl From for u8 { + fn from(s: SighashBase) -> Self { s as u8 } } #[cfg_attr(feature = "cargo-clippy", allow(clippy::doc_markdown))] @@ -50,16 +50,13 @@ pub struct Sighash { pub fork_id: bool, } -impl From for u32 { +impl From for u8 { fn from(s: Sighash) -> Self { - let base = s.base as u32; + let base = s.base as u8; let base = if s.anyone_can_pay { base | 0x80 } else { base }; + let base = if s.fork_id { base | 0x40 } else { base }; - if s.fork_id { - base | 0x40 - } else { - base - } + base } } @@ -73,7 +70,7 @@ impl Sighash { } /// Used by SCRIPT_VERIFY_STRICTENC - pub fn is_defined(version: SignatureVersion, u: u32) -> bool { + pub fn is_defined(version: SignatureVersion, u: u8) -> bool { // reset anyone_can_pay && fork_id (if applicable) bits let u = match version { SignatureVersion::ForkId => u & !(0x40 | 0x80), @@ -85,7 +82,7 @@ impl Sighash { } /// Creates Sighash from any u, even if is_defined() == false - pub fn from_u32(version: SignatureVersion, u: u32) -> Self { + pub fn from_u8(version: SignatureVersion, u: u8) -> Self { let anyone_can_pay = (u & 0x80) == 0x80; let fork_id = version == SignatureVersion::ForkId && (u & 0x40) == 0x40; let base = match u & 0x1f { @@ -233,9 +230,9 @@ impl TransactionInputSigner { input_amount: u64, script_pubkey: &Script, sigversion: SignatureVersion, - sighashtype: u32, + sighashtype: u8, ) -> H256 { - let sighash = Sighash::from_u32(sigversion, sighashtype); + let sighash = Sighash::from_u8(sigversion, sighashtype); match sigversion { SignatureVersion::ForkId if sighash.fork_id => { self.signature_hash_fork_id(input_index, input_amount, script_pubkey, sighashtype, sighash) @@ -258,12 +255,12 @@ impl TransactionInputSigner { input_amount: u64, script_pubkey: &Script, sigversion: SignatureVersion, - sighash: u32, + sighash: u8, ) -> TransactionInput { let hash = self.signature_hash(input_index, input_amount, script_pubkey, sigversion, sighash); let mut signature: Vec = keypair.private().sign(&hash).unwrap().into(); - signature.push(sighash as u8); + signature.push(sighash); let script_sig = Builder::default() .push_data(&signature) //.push_data(keypair.public()) @@ -282,7 +279,7 @@ impl TransactionInputSigner { &self, input_index: usize, script_pubkey: &Script, - sighashtype: u32, + sighashtype: u8, sighash: Sighash, ) -> H256 { if input_index >= self.inputs.len() { @@ -374,7 +371,8 @@ impl TransactionInputSigner { let mut stream = Stream::default(); stream.append(&tx); - stream.append(&sighashtype); + // FIXME: Serialize as u8 or u32? + stream.append(&(sighashtype as u32)); let out = stream.out(); match self.hash_algo { SignerHashAlgo::DSHA256 => dhash256(&out), @@ -387,7 +385,7 @@ impl TransactionInputSigner { input_index: usize, input_amount: u64, script_pubkey: &Script, - sighashtype: u32, + sighashtype: u8, sighash: Sighash, ) -> H256 { let hash_prevouts = compute_hash_prevouts(sighash, &self.inputs); @@ -404,7 +402,8 @@ impl TransactionInputSigner { stream.append(&self.inputs[input_index].sequence); stream.append(&hash_outputs); stream.append(&self.lock_time); - stream.append(&sighashtype); // this also includes 24-bit fork id. which is 0 for BitcoinCash + // FIXME: Serialize as u8 or u32? Also, 24-bit fork id? + stream.append(&(sighashtype as u32)); // this also includes 24-bit fork id. which is 0 for BitcoinCash let out = stream.out(); dhash256(&out) } @@ -414,7 +413,7 @@ impl TransactionInputSigner { input_index: usize, input_amount: u64, script_pubkey: &Script, - sighashtype: u32, + sighashtype: u8, sighash: Sighash, ) -> H256 { if input_index >= self.inputs.len() { @@ -436,7 +435,7 @@ impl TransactionInputSigner { &self, input_index: usize, script_pubkey: &Script, - sighashtype: u32, + sighashtype: u8, sighash: Sighash, ) -> Result { let mut sig_hash_stream = Stream::new(); @@ -553,7 +552,8 @@ impl TransactionInputSigner { sig_hash_stream.append(&self.lock_time); sig_hash_stream.append(&self.expiry_height); sig_hash_stream.append(&self.value_balance); - sig_hash_stream.append(&sighashtype); + // FIXME: Serialize as u8 or u32? + sig_hash_stream.append(&(sighashtype as u32)); sig_hash_stream.append(&self.inputs[input_index].previous_output); sig_hash_stream.append(&script_pubkey.to_bytes()); @@ -752,7 +752,7 @@ mod tests { tx: &'static str, script: &'static str, input_index: usize, - hash_type: i32, + hash_type: u8, result: &'static str, ) { let tx: Transaction = tx.into(); @@ -760,8 +760,8 @@ mod tests { let script: Script = script.into(); let expected = H256::from_reversed_str(result); - let sighash = Sighash::from_u32(SignatureVersion::Base, hash_type as u32); - let hash = signer.signature_hash_original(input_index, &script, hash_type as u32, sighash); + let sighash = Sighash::from_u8(SignatureVersion::Base, hash_type); + let hash = signer.signature_hash_original(input_index, &script, hash_type, sighash); assert_eq!(expected, hash); } @@ -800,7 +800,7 @@ mod tests { signer.inputs[0].amount = 50000000; signer.consensus_branch_id = 0x76b809bb; - let sig_hash = Sighash::from_u32(SignatureVersion::Base, 1); + let sig_hash = Sighash::from_u8(SignatureVersion::Base, 1); let hash = signer.signature_hash_overwintered( 0, &Script::from("1976a914507173527b4c3318a2aecd793bf1cfed705950cf88ac"), @@ -834,7 +834,7 @@ mod tests { signer.inputs[0].amount = 9924260; signer.consensus_branch_id = 0x76b809bb; - let sig_hash = Sighash::from_u32(SignatureVersion::Base, 1); + let sig_hash = Sighash::from_u8(SignatureVersion::Base, 1); let hash = signer.signature_hash_overwintered( 0, &Script::from("76a91405aab5342166f8594baf17a7d9bef5d56744332788ac"), @@ -868,7 +868,7 @@ mod tests { signer.inputs[0].amount = 100000000; signer.consensus_branch_id = 0x76b809bb; - let sig_hash = Sighash::from_u32(SignatureVersion::Base, 1); + let sig_hash = Sighash::from_u8(SignatureVersion::Base, 1); let hash = signer.signature_hash_overwintered( 0, &Script::from("6304e5928060b17521031c632dad67a611de77d9666cbc61e65957c7d7544c25e384f4e76de729e6a1bfac6782012088a914b78f0b837e2c710f8b28e59d06473d489e5315c88821037310a8fb9fd8f198a1a21db830252ad681fccda580ed4101f3f6bfb98b34fab5ac68"), diff --git a/mm2src/mm2_bitcoin/script/src/verify.rs b/mm2src/mm2_bitcoin/script/src/verify.rs index 804a856d34..2ba19a3ace 100644 --- a/mm2src/mm2_bitcoin/script/src/verify.rs +++ b/mm2src/mm2_bitcoin/script/src/verify.rs @@ -11,7 +11,7 @@ pub trait SignatureChecker { signature: &Signature, public: &Public, script_code: &Script, - sighashtype: u32, + sighashtype: u8, version: SignatureVersion, ) -> bool; @@ -23,7 +23,7 @@ pub trait SignatureChecker { pub struct NoopSignatureChecker; impl SignatureChecker for NoopSignatureChecker { - fn check_signature(&self, _: &Signature, _: &Public, _: &Script, _: u32, _: SignatureVersion) -> bool { false } + fn check_signature(&self, _: &Signature, _: &Public, _: &Script, _: u8, _: SignatureVersion) -> bool { false } fn check_lock_time(&self, _: Num) -> bool { false } @@ -43,7 +43,7 @@ impl SignatureChecker for TransactionSignatureChecker { signature: &Signature, public: &Public, script_code: &Script, - sighashtype: u32, + sighashtype: u8, version: SignatureVersion, ) -> bool { let hash = self From 9a7d81be4c181bc439bffc276730055d9d61a461 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sat, 27 Apr 2024 14:19:36 +0200 Subject: [PATCH 02/38] add fixmes, amend me --- mm2src/coins/utxo/utxo_common.rs | 11 ++++++++++ mm2src/mm2_main/src/lp_swap.rs | 1 + mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 21 ++++++++++++++------ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index e0dabb0a67..7d04db9b03 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -1102,6 +1102,7 @@ pub async fn validate_taker_funding_spend_preimage( let fee_div = expected_fee as f64 / actual_fee as f64; + // FIXME: Should negotiate the fee beforehand, accept fee >= negotiated_fee if !(0.9..=1.1).contains(&fee_div) { return MmError::err(ValidateTakerFundingSpendPreimageError::UnexpectedPreimageFee(format!( "Too large difference between expected {} and actual {} fees", @@ -3835,6 +3836,9 @@ pub fn get_trade_fee(coin: T) -> Box taker payment -> preimage (to the maker & dex) + // Chain B: maker payment -> claimation (to the taker) + // FIXME: Add taker payment fee + preimage fee + // Qs: + // 1- Who pays the maker payment fee? Take in considration that a nicer UX would be to hand the taker the full amount they requested. (so account for maker payment fee and taker claimation fee) let total_amount = &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount; let SwapPaymentOutputsResult { diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index 2263b0051d..d5f780e52b 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -766,6 +766,7 @@ pub fn lp_atomic_locktime_v2( if taker_coin.contains("-lightning") { // A good value for lightning taker locktime is about 24 hours to find a good 3 hop or less path for the payment get_payment_locktime() * 12 + // FIXME: Shouldn't BTC get x10 time, like in V1? } else if maker_coin == "BTC" || taker_coin == "BTC" || coin_with_4x_locktime(maker_coin) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 77b34e476f..42eb7631b4 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -793,11 +793,7 @@ impl { + TakerSwapEvent::Initialized { taker_payment_fee, .. } => { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); let taker_coin_ticker: String = self.taker_coin.ticker().into(); let new_locked = LockedAmountInfo { @@ -923,11 +919,14 @@ impl TransitionFrom> for TakerPaymentSent { } + +// FIXME: We should use consistent namings. FundingSpendPreimage is a partially signed TakerPayment. +// We should either call FundingSpendPreimage -> TakerPaymentPreimage or we call TakerPayment -> FundingSpend. impl TransitionFrom> for TakerPaymentSent From a844f62c161d9c8e4d97b87ff09b0d54335607f2 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 2 May 2024 23:42:14 +0200 Subject: [PATCH 03/38] Negotiate the taker payment spend fee Actually should be called funding spend fee or taker payment fee, but we are just following the current code naming at the moment. The negotiation goes as follows: 1- Taker and maker each decide how much this fee should be at the beginning of the swap. 2- The taker will send the maker their proposed fee during negotiation, if the maker deems the fee as low enough (less than 90% of the maker's own calculated fee), they will refuse to trade before the trade starts. Otherwise, they will continue and use this fee for validation later. 3- The maker will validate that the taker has accounted for this fee in the funding transaction. 4- The taker will validate that the taker payment preimage (generated by the maker) uses the negotiated fee or greater (greater number will deduct from the maker's trading volume anyway). If not, the taker will stop the trade since the maker is clearly stealing funds that isn't his which might affect the completion of the swap if the fee is low. --- mm2src/coins/lp_coins.rs | 12 +++ mm2src/coins/utxo/utxo_common.rs | 39 +++++---- .../src/lp_swap/komodefi.swap_v2.pb.rs | 2 + mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 21 ++++- mm2src/mm2_main/src/lp_swap/swap_v2.proto | 1 + mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 85 ++++++++++++++++--- 6 files changed, 131 insertions(+), 29 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 9b6c465f7b..eabb2193d8 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1236,6 +1236,8 @@ pub struct SendTakerFundingArgs<'a> { pub maker_pub: &'a [u8], /// DEX fee pub dex_fee: &'a DexFee, + /// The extra fee added to the trading volume to cover the taker payment spend transaction fees + pub taker_payment_spend_fee: BigDecimal, /// Additional reward for maker (premium) pub premium_amount: BigDecimal, /// Actual volume of taker's payment @@ -1272,6 +1274,8 @@ pub struct GenTakerFundingSpendArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub taker_payment_time_lock: u64, /// The hash of the secret generated by maker pub maker_secret_hash: &'a [u8], + /// The extra fee added to the trading volume to cover the taker payment spend transaction fees + pub taker_payment_spend_fee: BigDecimal, } /// Helper struct wrapping arguments for [TakerCoinSwapOpsV2::validate_taker_funding] @@ -1286,6 +1290,8 @@ pub struct ValidateTakerFundingArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub other_pub: &'a Coin::Pubkey, /// DEX fee amount pub dex_fee: &'a DexFee, + /// The extra fee added to the trading volume to cover the taker payment spend transaction fees + pub taker_payment_spend_fee: BigDecimal, /// Additional reward for maker (premium) pub premium_amount: BigDecimal, /// Actual volume of taker's payment @@ -1394,6 +1400,8 @@ impl From for ValidateSwapV2TxError { /// Enum covering error cases that can happen during taker funding spend preimage validation. #[derive(Debug, Display, EnumFromStringify)] pub enum ValidateTakerFundingSpendPreimageError { + /// Error during conversion of BigDecimal amount to coin's specific monetary units (satoshis, wei, etc.). + NumConversion(String), /// Funding tx has no outputs FundingTxNoOutputs, /// Actual preimage fee is either too high or too small @@ -1414,6 +1422,10 @@ pub enum ValidateTakerFundingSpendPreimageError { Rpc(String), } +impl From for ValidateTakerFundingSpendPreimageError { + fn from(err: NumConversError) -> Self { ValidateTakerFundingSpendPreimageError::NumConversion(err.to_string()) } +} + impl From for ValidateTakerFundingSpendPreimageError { fn from(err: TxGenError) -> Self { ValidateTakerFundingSpendPreimageError::TxGenError(format!("{:?}", err)) } } diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 7d04db9b03..5bfc2af91f 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -1003,8 +1003,17 @@ async fn gen_taker_funding_spend_preimage( let fee = match fee { FundingSpendFeeSetting::GetFromCoin => { - coin.get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE, &FeeApproxStage::WithoutApprox) - .await? + let calculated_fee = coin + .get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE, &FeeApproxStage::WithoutApprox) + .await?; + let taker_instructed_fee = + sat_from_big_decimal(&args.taker_payment_spend_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; + // If calculated fee is less than instructed fee, use instructed fee because it was never intended + // to be deposited to us (maker). If the calculated fee is larger, we will incur the fee difference + // just to make sure the transaction is confirmed quickly. + // FIXME: Possible abuse vector is that the taker can always send the fee to be just above 90% of the + // expected fee knowing that the maker will always accept incurring the difference. + calculated_fee.max(taker_instructed_fee) }, FundingSpendFeeSetting::UseExact(f) => f, }; @@ -1094,19 +1103,14 @@ pub async fn validate_taker_funding_spend_preimage( ))); } - let expected_fee = coin - .get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE, &FeeApproxStage::WithoutApprox) - .await?; - let actual_fee = funding_amount - payment_amount; + let instructed_fee = + sat_from_big_decimal(&gen_args.taker_payment_spend_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; - let fee_div = expected_fee as f64 / actual_fee as f64; - - // FIXME: Should negotiate the fee beforehand, accept fee >= negotiated_fee - if !(0.9..=1.1).contains(&fee_div) { + if actual_fee < instructed_fee { return MmError::err(ValidateTakerFundingSpendPreimageError::UnexpectedPreimageFee(format!( - "Too large difference between expected {} and actual {} fees", - expected_fee, actual_fee + "A fee of {} was used, less than the agreed upon fee of {}", + actual_fee, instructed_fee ))); } @@ -4831,7 +4835,10 @@ where // FIXME: Add taker payment fee + preimage fee // Qs: // 1- Who pays the maker payment fee? Take in considration that a nicer UX would be to hand the taker the full amount they requested. (so account for maker payment fee and taker claimation fee) - let total_amount = &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount; + let total_amount = &args.dex_fee.total_spend_amount().to_decimal() + + &args.premium_amount + + &args.trading_amount + + &args.taker_payment_spend_fee; let SwapPaymentOutputsResult { payment_address, @@ -4923,8 +4930,10 @@ where T: UtxoCommonOps + SwapOps, { let maker_htlc_key_pair = coin.derive_htlc_key_pair(args.swap_unique_data); - let total_expected_amount = - &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount; + let total_expected_amount = &args.dex_fee.total_spend_amount().to_decimal() + + &args.premium_amount + + &args.trading_amount + + &args.taker_payment_spend_fee; let expected_amount_sat = sat_from_big_decimal(&total_expected_amount, coin.as_ref().decimals)?; diff --git a/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs b/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs index 130fb2e3e1..da06b76b20 100644 --- a/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs +++ b/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs @@ -53,6 +53,8 @@ pub struct TakerNegotiationData { pub maker_coin_swap_contract: ::core::option::Option<::prost::alloc::vec::Vec>, #[prost(bytes = "vec", optional, tag = "8")] pub taker_coin_swap_contract: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(uint64, tag = "9")] + pub taker_payment_spend_fee: u64, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 25c0ff8344..f10da6c39f 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -21,9 +21,10 @@ use keys::KeyPair; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_libp2p::Secp256k1PubkeySerialize; -use mm2_number::MmNumber; +use mm2_number::{BigDecimal, MmNumber}; use mm2_state_machine::prelude::*; use mm2_state_machine::storable_state_machine::*; +use num_traits::ToPrimitive; use primitives::hash::H256; use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; use secp256k1::PublicKey; @@ -55,6 +56,7 @@ pub struct StoredNegotiationData { maker_coin_swap_contract: Option, taker_coin_swap_contract: Option, taker_secret_hash: BytesJson, + taker_payment_spend_fee: BigDecimal, } /// Represents events produced by maker swap states. @@ -822,6 +824,8 @@ impl fee, @@ -968,6 +972,14 @@ impl p, @@ -997,6 +1009,7 @@ impl>, taker_coin_swap_contract: Option>, taker_secret_hash: Vec, + taker_payment_spend_fee: BigDecimal, } impl NegotiationData { @@ -1024,6 +1038,7 @@ impl Negotiation maker_coin_swap_contract: self.maker_coin_swap_contract.clone().map(|b| b.into()), taker_coin_swap_contract: self.taker_coin_swap_contract.clone().map(|b| b.into()), taker_secret_hash: self.taker_secret_hash.clone().into(), + taker_payment_spend_fee: self.taker_payment_spend_fee.clone(), } } @@ -1044,6 +1059,7 @@ impl Negotiation maker_coin_swap_contract: None, taker_coin_swap_contract: None, taker_secret_hash: stored.taker_secret_hash.into(), + taker_payment_spend_fee: stored.taker_payment_spend_fee, }) } } @@ -1161,6 +1177,7 @@ impl Box::new(Initialized { maker_coin: Default::default(), @@ -501,6 +507,7 @@ impl Box::new(Negotiated { maker_coin_start_block, @@ -518,6 +526,7 @@ impl Box::new(TakerFundingSent { maker_coin_start_block, taker_coin_start_block, @@ -537,6 +547,7 @@ impl { + TakerSwapEvent::Initialized { + taker_payment_fee, + taker_payment_spend_fee, + .. + } => { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); let taker_coin_ticker: String = self.taker_coin.ticker().into(); let new_locked = LockedAmountInfo { swap_uuid: self.uuid, locked_amount: LockedAmount { coin: taker_coin_ticker.clone(), - amount: &(&self.taker_volume + &self.dex_fee.total_spend_amount()) + &self.taker_premium, + amount: &(&self.taker_volume + &self.dex_fee.total_spend_amount()) + + &(&self.taker_premium + &taker_payment_spend_fee.amount.clone().into()), trade_fee: Some(taker_payment_fee.clone().into()), }, }; @@ -839,15 +857,24 @@ impl::DbRepr as StateMachineDbRepr>::Event, ) { match event { - TakerSwapEvent::Initialized { taker_payment_fee, .. } - | TakerSwapEvent::Negotiated { taker_payment_fee, .. } => { + TakerSwapEvent::Initialized { + taker_payment_fee, + taker_payment_spend_fee, + .. + } + | TakerSwapEvent::Negotiated { + taker_payment_fee, + taker_payment_spend_fee, + .. + } => { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); let taker_coin_ticker: String = self.taker_coin.ticker().into(); let new_locked = LockedAmountInfo { swap_uuid: self.uuid, locked_amount: LockedAmount { coin: taker_coin_ticker.clone(), - amount: &(&self.taker_volume + &self.dex_fee.total_spend_amount()) + &self.taker_premium, + amount: &(&self.taker_volume + &self.dex_fee.total_spend_amount()) + + &(&self.taker_premium + &taker_payment_spend_fee.amount.into()), trade_fee: Some(taker_payment_fee.into()), }, }; @@ -919,14 +946,23 @@ impl fee, + Err(e) => { + let reason = AbortReason::FailedToGetTakerPaymentSpendFee(e.to_string()); + return Self::change_state(Aborted::new(reason), state_machine).await; + }, + }; - // FIXME: This is not taker payment tx fee, this is the funding tx fee. + // TODO: Add the price of maker payment fee (in taker coin) + preimage fee to the total payment value. + let total_payment_value = &(&state_machine.taker_volume + &state_machine.dex_fee.total_spend_amount()) + + &(&state_machine.taker_premium + &taker_payment_spend_fee.amount); + let preimage_value = TradePreimageValue::Exact(total_payment_value.to_decimal()); + + // FIXME: This is not taker payment tx fee, this is the funding tx fee, use consistent naming. let taker_payment_fee = match state_machine .taker_coin .get_sender_trade_fee(preimage_value, stage) @@ -984,6 +1020,7 @@ impl { maker_coin_start_block: u64, taker_coin_start_block: u64, taker_payment_fee: SavedTradeFee, + taker_payment_spend_fee: SavedTradeFee, maker_payment_spend_fee: SavedTradeFee, } @@ -1014,6 +1052,7 @@ impl, taker_payment_fee: SavedTradeFee, + taker_payment_spend_fee: SavedTradeFee, maker_payment_spend_fee: SavedTradeFee, } @@ -1231,6 +1276,7 @@ impl, + taker_payment_spend_fee: SavedTradeFee, } #[async_trait] @@ -1304,6 +1353,8 @@ impl, + taker_payment_spend_fee: SavedTradeFee, taker_funding: TakerCoin::Tx, funding_spend_preimage: TxPreimageWithSig, maker_payment: MakerCoin::Tx, @@ -1443,6 +1497,7 @@ impl Date: Fri, 3 May 2024 11:49:06 +0200 Subject: [PATCH 04/38] Use `big_decimal_from_sat` & `sat_from_big_decimal` for conversions to u64 The big decimal might be a fraction less than zero and gets converted to zero when sent over the wire (because we send the fee as u64). Scale it properly before sending it. --- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 17 ++++++++++------- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 10 +++++++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index f10da6c39f..1e978720fb 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -8,6 +8,7 @@ use crate::mm2::lp_swap::{broadcast_swap_v2_msg_every, check_balance_for_maker_s SwapConfirmationsSettings, TransactionIdentifier, MAKER_SWAP_V2_TYPE, MAX_STARTED_AT_DIFF}; use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; +use coins::utxo::utxo_common::big_decimal_from_sat_unsigned; use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, ParseCoinAssocTypes, RefundMakerPaymentArgs, RefundPaymentArgs, SearchForFundingSpendErr, SendMakerPaymentArgs, SwapTxTypeWithSecretHash, @@ -24,7 +25,6 @@ use mm2_libp2p::Secp256k1PubkeySerialize; use mm2_number::{BigDecimal, MmNumber}; use mm2_state_machine::prelude::*; use mm2_state_machine::storable_state_machine::*; -use num_traits::ToPrimitive; use primitives::hash::H256; use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; use secp256k1::PublicKey; @@ -972,10 +972,13 @@ impl Date: Fri, 3 May 2024 13:16:34 +0200 Subject: [PATCH 05/38] fix tests --- mm2src/mm2_bitcoin/script/src/sign.rs | 22 +++++---- .../tests/docker_tests/swap_proto_v2_tests.rs | 45 +++++++++++++------ 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/mm2src/mm2_bitcoin/script/src/sign.rs b/mm2src/mm2_bitcoin/script/src/sign.rs index 4185a9a756..44e7b4fdce 100644 --- a/mm2src/mm2_bitcoin/script/src/sign.rs +++ b/mm2src/mm2_bitcoin/script/src/sign.rs @@ -52,9 +52,9 @@ pub struct Sighash { impl From for u8 { fn from(s: Sighash) -> Self { - let base = s.base as u8; - let base = if s.anyone_can_pay { base | 0x80 } else { base }; - let base = if s.fork_id { base | 0x40 } else { base }; + let mut base = s.base as u8; + base = if s.anyone_can_pay { base | 0x80 } else { base }; + base = if s.fork_id { base | 0x40 } else { base }; base } @@ -767,15 +767,13 @@ mod tests { #[test] fn test_sighash_forkid_from_u32() { - assert!(!Sighash::is_defined(SignatureVersion::Base, 0xFFFFFF82)); - assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000182)); - assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000080)); - assert!(Sighash::is_defined(SignatureVersion::Base, 0x00000001)); - assert!(Sighash::is_defined(SignatureVersion::Base, 0x00000082)); - assert!(Sighash::is_defined(SignatureVersion::Base, 0x00000003)); - - assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0xFFFFFFC2)); - assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0x000001C2)); + assert!(!Sighash::is_defined(SignatureVersion::Base, 0x80)); + assert!(!Sighash::is_defined(SignatureVersion::Base, 0x84)); + assert!(!Sighash::is_defined(SignatureVersion::Base, 0x85)); + assert!(Sighash::is_defined(SignatureVersion::Base, 0x01)); + assert!(Sighash::is_defined(SignatureVersion::Base, 0x82)); + assert!(Sighash::is_defined(SignatureVersion::Base, 0x03)); + assert!(Sighash::is_defined(SignatureVersion::ForkId, 0x00000081)); assert!(Sighash::is_defined(SignatureVersion::ForkId, 0x000000C2)); assert!(Sighash::is_defined(SignatureVersion::ForkId, 0x00000043)); diff --git a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs index fbc632aa47..534f65b9b1 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs @@ -7,7 +7,7 @@ use coins::{ConfirmPaymentInput, DexFee, FundingTxSpend, GenTakerFundingSpendArg TakerCoinSwapOpsV2, Transaction, ValidateMakerPaymentArgs, ValidateTakerFundingArgs}; use common::{block_on, now_sec, DEX_FEE_ADDR_RAW_PUBKEY}; use futures01::Future; -use mm2_number::MmNumber; +use mm2_number::{BigDecimal, MmNumber}; use mm2_test_helpers::for_tests::{active_swaps, check_recent_swaps, coins_needed_for_kickstart, disable_coin, disable_coin_err, enable_native, get_locked_amount, mm_dump, my_swap_status, mycoin1_conf, mycoin_conf, start_swaps, wait_for_swap_finished, @@ -26,12 +26,14 @@ fn send_and_refund_taker_funding_timelock() { let taker_secret_hash = &[0; 20]; let maker_pub = coin.my_public_key().unwrap(); let dex_fee = &DexFee::Standard("0.01".into()); + let taker_payment_spend_fee: BigDecimal = "0.002".parse().unwrap(); let send_args = SendTakerFundingArgs { time_lock, taker_secret_hash, maker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), swap_unique_data: &[], @@ -41,8 +43,8 @@ fn send_and_refund_taker_funding_timelock() { // tx must have 3 outputs: actual funding, OP_RETURN containing the secret hash and change assert_eq!(3, taker_funding_utxo_tx.outputs.len()); - // dex_fee_amount + premium_amount + trading_amount - let expected_amount = 111000000u64; + // dex_fee_amount + premium_amount + trading_amount + taker_payment_spend_fee + let expected_amount = 111200000u64; assert_eq!(expected_amount, taker_funding_utxo_tx.outputs[0].value); let expected_op_return = Builder::default() @@ -57,6 +59,7 @@ fn send_and_refund_taker_funding_timelock() { taker_secret_hash, other_pub: maker_pub, dex_fee, + taker_payment_spend_fee, premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), swap_unique_data: &[], @@ -106,12 +109,14 @@ fn send_and_refund_taker_funding_secret() { let taker_secret_hash = taker_secret_hash_owned.as_slice(); let maker_pub = coin.my_public_key().unwrap(); let dex_fee = &DexFee::Standard("0.01".into()); + let taker_payment_spend_fee: BigDecimal = "0.002".parse().unwrap(); let send_args = SendTakerFundingArgs { time_lock, taker_secret_hash, maker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), swap_unique_data: &[], @@ -121,8 +126,8 @@ fn send_and_refund_taker_funding_secret() { // tx must have 3 outputs: actual funding, OP_RETURN containing the secret hash and change assert_eq!(3, taker_funding_utxo_tx.outputs.len()); - // dex_fee_amount + premium_amount + trading_amount - let expected_amount = 111000000u64; + // dex_fee_amount + premium_amount + trading_amount + taker_payment_spend_fee + let expected_amount = 111200000u64; assert_eq!(expected_amount, taker_funding_utxo_tx.outputs[0].value); let expected_op_return = Builder::default() @@ -137,6 +142,7 @@ fn send_and_refund_taker_funding_secret() { taker_secret_hash, other_pub: maker_pub, dex_fee, + taker_payment_spend_fee, premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), swap_unique_data: &[], @@ -190,12 +196,14 @@ fn send_and_spend_taker_funding() { let maker_pub = maker_coin.my_public_key().unwrap(); let dex_fee = &DexFee::Standard("0.01".into()); + let taker_payment_spend_fee: BigDecimal = "0.002".parse().unwrap(); let send_args = SendTakerFundingArgs { time_lock: funding_time_lock, taker_secret_hash, maker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), swap_unique_data: &[], @@ -205,8 +213,8 @@ fn send_and_spend_taker_funding() { // tx must have 3 outputs: actual funding, OP_RETURN containing the secret hash and change assert_eq!(3, taker_funding_utxo_tx.outputs.len()); - // dex_fee_amount + premium_amount + trading_amount - let expected_amount = 111000000u64; + // dex_fee_amount + premium_amount + trading_amount + taker_payment_spend_fee + let expected_amount = 111200000u64; assert_eq!(expected_amount, taker_funding_utxo_tx.outputs[0].value); let expected_op_return = Builder::default() @@ -221,6 +229,7 @@ fn send_and_spend_taker_funding() { taker_secret_hash, other_pub: taker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: "0.1".parse().unwrap(), trading_amount: 1.into(), swap_unique_data: &[], @@ -235,6 +244,7 @@ fn send_and_spend_taker_funding() { taker_secret_hash, taker_payment_time_lock: 0, maker_secret_hash: &[0; 20], + taker_payment_spend_fee, }; let preimage = block_on(maker_coin.gen_taker_funding_spend_preimage(&preimage_args, &[])).unwrap(); @@ -277,12 +287,14 @@ fn send_and_spend_taker_payment_dex_fee_burn() { let maker_pub = maker_coin.my_public_key().unwrap(); let dex_fee = &DexFee::with_burn("0.75".into(), "0.25".into()); + let taker_payment_spend_fee: BigDecimal = "0.2".parse().unwrap(); let send_args = SendTakerFundingArgs { time_lock: funding_time_lock, taker_secret_hash, maker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: 0.into(), trading_amount: 777.into(), swap_unique_data: &[], @@ -292,8 +304,8 @@ fn send_and_spend_taker_payment_dex_fee_burn() { // tx must have 3 outputs: actual funding, OP_RETURN containing the secret hash and change assert_eq!(3, taker_funding_utxo_tx.outputs.len()); - // dex_fee_amount (with burn) + premium_amount (zero) + trading_amount - let expected_amount = 77800000000u64; + // dex_fee_amount (with burn) + premium_amount (zero) + trading_amount + taker_payment_spend_fee + let expected_amount = 77820000000u64; assert_eq!(expected_amount, taker_funding_utxo_tx.outputs[0].value); let expected_op_return = Builder::default() @@ -308,6 +320,7 @@ fn send_and_spend_taker_payment_dex_fee_burn() { taker_secret_hash, other_pub: taker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: 0.into(), trading_amount: 777.into(), swap_unique_data: &[], @@ -322,6 +335,7 @@ fn send_and_spend_taker_payment_dex_fee_burn() { taker_secret_hash, taker_payment_time_lock: 0, maker_secret_hash, + taker_payment_spend_fee, }; let preimage = block_on(maker_coin.gen_taker_funding_spend_preimage(&preimage_args, &[])).unwrap(); @@ -347,7 +361,8 @@ fn send_and_spend_taker_payment_dex_fee_burn() { assert_eq!(taker_payment_spend_preimage.preimage.outputs.len(), 3); assert_eq!(taker_payment_spend_preimage.preimage.outputs[0].value, 75000000); assert_eq!(taker_payment_spend_preimage.preimage.outputs[1].value, 25000000); - assert_eq!(taker_payment_spend_preimage.preimage.outputs[2].value, 77699998000); + // Should have been 777, but a preimage fee was deducted, we should account for that so the taker receives full amount. + assert_eq!(taker_payment_spend_preimage.preimage.outputs[2].value, 77699999000); block_on( maker_coin.validate_taker_payment_spend_preimage(&gen_taker_payment_spend_args, &taker_payment_spend_preimage), @@ -380,12 +395,14 @@ fn send_and_spend_taker_payment_standard_dex_fee() { let maker_pub = maker_coin.my_public_key().unwrap(); let dex_fee = &DexFee::Standard(1.into()); + let taker_payment_spend_fee: BigDecimal = "0.2".parse().unwrap(); let send_args = SendTakerFundingArgs { time_lock: funding_time_lock, taker_secret_hash, maker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: 0.into(), trading_amount: 777.into(), swap_unique_data: &[], @@ -396,7 +413,7 @@ fn send_and_spend_taker_payment_standard_dex_fee() { assert_eq!(3, taker_funding_utxo_tx.outputs.len()); // dex_fee_amount (with burn) + premium_amount (zero) + trading_amount - let expected_amount = 77800000000u64; + let expected_amount = 77820000000u64; assert_eq!(expected_amount, taker_funding_utxo_tx.outputs[0].value); let expected_op_return = Builder::default() @@ -411,6 +428,7 @@ fn send_and_spend_taker_payment_standard_dex_fee() { taker_secret_hash, other_pub: taker_pub, dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), premium_amount: 0.into(), trading_amount: 777.into(), swap_unique_data: &[], @@ -425,6 +443,7 @@ fn send_and_spend_taker_payment_standard_dex_fee() { taker_secret_hash, taker_payment_time_lock: 0, maker_secret_hash, + taker_payment_spend_fee, }; let preimage = block_on(maker_coin.gen_taker_funding_spend_preimage(&preimage_args, &[])).unwrap(); @@ -651,7 +670,7 @@ fn test_v2_swap_utxo_utxo() { let locked_alice = block_on(get_locked_amount(&mm_alice, MYCOIN1)); assert_eq!(locked_alice.coin, MYCOIN1); - let expected: MmNumberMultiRepr = MmNumber::from("778.00001").into(); + let expected: MmNumberMultiRepr = MmNumber::from("778.00002").into(); assert_eq!(locked_alice.locked_amount, expected); // amount must unlocked after funding tx is sent @@ -776,7 +795,7 @@ fn test_v2_swap_utxo_utxo_kickstart() { // coins must be virtually locked after kickstart until swap transactions are sent let locked_alice = block_on(get_locked_amount(&mm_alice, MYCOIN1)); assert_eq!(locked_alice.coin, MYCOIN1); - let expected: MmNumberMultiRepr = MmNumber::from("778.00001").into(); + let expected: MmNumberMultiRepr = MmNumber::from("778.00002").into(); assert_eq!(locked_alice.locked_amount, expected); let locked_bob = block_on(get_locked_amount(&mm_bob, MYCOIN)); From ef28a6ce6a0cfcca0e099814d781317ebf1e8db9 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 3 May 2024 20:10:08 +0200 Subject: [PATCH 06/38] can't clamp the fee to 1 since it's probably higher than the fee noticed this in the integration tests, the fee might be a fraction so clamping it to one yields a fee higher than the actually one, thus fails the ratio check --- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 1e978720fb..fcc7b70dfb 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -972,11 +972,17 @@ impl Date: Fri, 3 May 2024 21:49:34 +0200 Subject: [PATCH 07/38] remove wrong transition --- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 0fd8d04947..1e62c97ca1 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -1924,10 +1924,6 @@ impl TransitionFrom> for TakerPaymentRefundRequired { } -impl - TransitionFrom> for TakerPaymentRefundRequired -{ -} #[async_trait] impl State From ad21f4e54e7adb9d22fed10384cf66e500571d76 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sat, 4 May 2024 16:56:04 +0200 Subject: [PATCH 08/38] add some tests --- .../tests/docker_tests/swap_proto_v2_tests.rs | 120 +++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs index 534f65b9b1..6c8bf03da6 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs @@ -4,7 +4,8 @@ use coins::utxo::UtxoCommonOps; use coins::{ConfirmPaymentInput, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MarketCoinOps, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundMakerPaymentArgs, RefundPaymentArgs, SendMakerPaymentArgs, SendTakerFundingArgs, SwapTxTypeWithSecretHash, - TakerCoinSwapOpsV2, Transaction, ValidateMakerPaymentArgs, ValidateTakerFundingArgs}; + TakerCoinSwapOpsV2, Transaction, ValidateMakerPaymentArgs, ValidateSwapV2TxError, + ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageError}; use common::{block_on, now_sec, DEX_FEE_ADDR_RAW_PUBKEY}; use futures01::Future; use mm2_number::{BigDecimal, MmNumber}; @@ -271,6 +272,123 @@ fn send_and_spend_taker_funding() { } } +#[test] +fn reject_funding_low_taker_payment_spend_fee() { + let (_mm_arc, taker_coin, _privkey) = generate_utxo_coin_with_random_privkey(MYCOIN, 1000.into()); + let (_mm_arc, maker_coin, _privkey) = generate_utxo_coin_with_random_privkey(MYCOIN, 1000.into()); + + let funding_time_lock = now_sec() - 1000; + let taker_secret_hash = &[0; 20]; + + let taker_pub = taker_coin.my_public_key().unwrap(); + let maker_pub = maker_coin.my_public_key().unwrap(); + + let dex_fee = &DexFee::Standard("0.01".into()); + let taker_payment_spend_fee: BigDecimal = "0.002".parse().unwrap(); + + let send_args = SendTakerFundingArgs { + time_lock: funding_time_lock, + taker_secret_hash, + maker_pub, + dex_fee, + // The taker uses a lower taker payment spend fee in the taker funding tx + taker_payment_spend_fee: "0.001".parse().unwrap(), + premium_amount: "0.1".parse().unwrap(), + trading_amount: 1.into(), + swap_unique_data: &[], + }; + let taker_funding_utxo_tx = block_on(taker_coin.send_taker_funding(send_args)).unwrap(); + log!("Funding tx {:02x}", taker_funding_utxo_tx.tx_hash()); + + let validate_args = ValidateTakerFundingArgs { + funding_tx: &taker_funding_utxo_tx, + time_lock: funding_time_lock, + taker_secret_hash, + other_pub: taker_pub, + dex_fee, + taker_payment_spend_fee, + premium_amount: "0.1".parse().unwrap(), + trading_amount: 1.into(), + swap_unique_data: &[], + }; + // The maker should reject the taker funding tx because the taker didn't use the agreed upon taker payment spend fee + let err = block_on(maker_coin.validate_taker_funding(validate_args)) + .unwrap_err() + .into_inner(); + assert!(matches!(err, ValidateSwapV2TxError::InvalidDestinationOrAmount(..))) +} + +#[test] +fn reject_preimage_low_taker_payment_spend_fee() { + let (_mm_arc, taker_coin, _privkey) = generate_utxo_coin_with_random_privkey(MYCOIN, 1000.into()); + let (_mm_arc, maker_coin, _privkey) = generate_utxo_coin_with_random_privkey(MYCOIN, 1000.into()); + + let funding_time_lock = now_sec() - 1000; + let taker_secret_hash = &[0; 20]; + + let maker_secret = &[1; 32]; + let maker_secret_hash_owned = dhash160(maker_secret); + let maker_secret_hash = maker_secret_hash_owned.as_slice(); + + let taker_pub = taker_coin.my_public_key().unwrap(); + let maker_pub = maker_coin.my_public_key().unwrap(); + + let dex_fee = &DexFee::Standard("0.01".into()); + let taker_payment_spend_fee: BigDecimal = "0.002".parse().unwrap(); + + let send_args = SendTakerFundingArgs { + time_lock: funding_time_lock, + taker_secret_hash, + maker_pub, + dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), + premium_amount: "0.1".parse().unwrap(), + trading_amount: 1.into(), + swap_unique_data: &[], + }; + let taker_funding_utxo_tx = block_on(taker_coin.send_taker_funding(send_args)).unwrap(); + log!("Funding tx {:02x}", taker_funding_utxo_tx.tx_hash()); + + let validate_args = ValidateTakerFundingArgs { + funding_tx: &taker_funding_utxo_tx, + time_lock: funding_time_lock, + taker_secret_hash, + other_pub: taker_pub, + dex_fee, + taker_payment_spend_fee: taker_payment_spend_fee.clone(), + premium_amount: "0.1".parse().unwrap(), + trading_amount: 1.into(), + swap_unique_data: &[], + }; + block_on(maker_coin.validate_taker_funding(validate_args)).unwrap(); + + let mut preimage_args = GenTakerFundingSpendArgs { + funding_tx: &taker_funding_utxo_tx, + maker_pub, + taker_pub, + funding_time_lock, + taker_secret_hash, + taker_payment_time_lock: 0, + maker_secret_hash, + // Use a lower taker payment spend fee in the preimage. + // Note that this is a lower bound, the generated preimage fee might be higher at the end. + taker_payment_spend_fee: "0.001".parse().unwrap(), + }; + let preimage = block_on(maker_coin.gen_taker_funding_spend_preimage(&preimage_args, &[])).unwrap(); + + // Set back the taker payment spend fee to the previous value for checking. + preimage_args.taker_payment_spend_fee = taker_payment_spend_fee; + // The taker should reject the preimage because the taker payment spend fee is lower than agreed upon. + // Means that the maker stole the fee amount for themselves. + let err = block_on(taker_coin.validate_taker_funding_spend_preimage(&preimage_args, &preimage)) + .unwrap_err() + .into_inner(); + assert!(matches!( + err, + ValidateTakerFundingSpendPreimageError::UnexpectedPreimageFee(..) + )) +} + #[test] fn send_and_spend_taker_payment_dex_fee_burn() { let (_mm_arc, taker_coin, _privkey) = generate_utxo_coin_with_random_privkey(MYCOIN, 1000.into()); From ff05d06b84fdb7e87dd93e5a2fa241004d8ef40d Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 8 May 2024 21:39:08 +0200 Subject: [PATCH 09/38] add a calculator for taker payment spend transaction size --- mm2src/coins/utxo/utxo_common.rs | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 5bfc2af91f..9ebeac522a 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -875,6 +875,73 @@ enum FundingSpendFeeSetting { UseExact(u64), } +/// Returns the taker payment spend transaction size in vbytes. +async fn get_taker_payment_spend_transaction_size(coin: &impl UtxoCommonOps) -> usize { + let preimage = TransactionInputSigner { + lock_time: 0, + version: coin.as_ref().conf.tx_version, + n_time: None, + overwintered: coin.as_ref().conf.overwintered, + inputs: vec![UnsignedTransactionInput { + sequence: SEQUENCE_FINAL, + previous_output: OutPoint { + hash: H256::default(), + index: DEFAULT_SWAP_VOUT as u32, + }, + amount: 0, + witness: Vec::new(), + }], + outputs: vec![TransactionOutput { + value: 0, + script_pubkey: Builder::build_p2sh(&AddressHashEnum::default_address_hash()).to_bytes(), + }], + expiry_height: 0, + join_splits: vec![], + shielded_spends: vec![], + shielded_outputs: vec![], + value_balance: 0, + version_group_id: coin.as_ref().conf.version_group_id, + consensus_branch_id: coin.as_ref().conf.consensus_branch_id, + zcash: coin.as_ref().conf.zcash, + posv: coin.as_ref().conf.is_posv, + str_d_zeel: None, + hash_algo: coin.as_ref().tx_hash_algo.into(), + }; + + let redeem_script = + swap_proto_v2_scripts::taker_funding_script(0, &H160::default(), &Public::default(), &Public::default()); + + let mut signature = calc_and_sign_sighash( + &preimage, + DEFAULT_SWAP_VOUT, + &redeem_script, + &KeyPair::random_compressed(), + coin.as_ref().conf.signature_version, + SIGHASH_ALL, + coin.as_ref().conf.fork_id, + ) + // This won't fail since the keypair is a valid keypair and we have + // an output in the preimage that corresponds to `DEFAULT_SWAP_VOUT`. + .unwrap() + .to_vec(); + signature.push(SIGHASH_ALL | coin.as_ref().conf.fork_id); + + let maker_signature = &signature; + let taker_signature = &signature; + + let mut final_tx: UtxoTx = preimage.into(); + final_tx.inputs[0].script_sig = Builder::default() + .push_data(&maker_signature) + .push_data(&taker_signature) + .push_opcode(Opcode::OP_1) + .push_opcode(Opcode::OP_0) + .push_data(&redeem_script) + .into_bytes(); + + // We aren't spending from the segwit address, we are spending from a P2SH address. + tx_size_in_v_bytes(&UtxoAddressFormat::Standard, &final_tx) +} + async fn p2sh_spending_tx_preimage( coin: &T, prev_tx: &UtxoTx, From c20bac22d83d15798dc8f21398b3bafd36193e9b Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 8 May 2024 22:10:23 +0200 Subject: [PATCH 10/38] don't actually sign anything to avoid unwrapping use a signature-size dummy date instead --- mm2src/coins/utxo/utxo_common.rs | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 9ebeac522a..9e98472497 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -911,28 +911,12 @@ async fn get_taker_payment_spend_transaction_size(coin: &impl UtxoCommonOps) -> let redeem_script = swap_proto_v2_scripts::taker_funding_script(0, &H160::default(), &Public::default(), &Public::default()); - let mut signature = calc_and_sign_sighash( - &preimage, - DEFAULT_SWAP_VOUT, - &redeem_script, - &KeyPair::random_compressed(), - coin.as_ref().conf.signature_version, - SIGHASH_ALL, - coin.as_ref().conf.fork_id, - ) - // This won't fail since the keypair is a valid keypair and we have - // an output in the preimage that corresponds to `DEFAULT_SWAP_VOUT`. - .unwrap() - .to_vec(); - signature.push(SIGHASH_ALL | coin.as_ref().conf.fork_id); - - let maker_signature = &signature; - let taker_signature = &signature; - let mut final_tx: UtxoTx = preimage.into(); final_tx.inputs[0].script_sig = Builder::default() - .push_data(&maker_signature) - .push_data(&taker_signature) + // Maximum of 72 byte maker signature. + .push_data(&[0; 72]) + // Maximum of 72 byte taker signature. + .push_data(&[0; 72]) .push_opcode(Opcode::OP_1) .push_opcode(Opcode::OP_0) .push_data(&redeem_script) From 2ff43adc2ff124364a364f26d6a9efffade0089a Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 8 May 2024 22:19:05 +0200 Subject: [PATCH 11/38] account for the sighash byte --- mm2src/coins/utxo/utxo_common.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 9e98472497..e8c2ce8cdb 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -913,10 +913,10 @@ async fn get_taker_payment_spend_transaction_size(coin: &impl UtxoCommonOps) -> let mut final_tx: UtxoTx = preimage.into(); final_tx.inputs[0].script_sig = Builder::default() - // Maximum of 72 byte maker signature. - .push_data(&[0; 72]) - // Maximum of 72 byte taker signature. - .push_data(&[0; 72]) + // Maximum of 72 byte maker signature + a sighash byte. + .push_data(&[0; 72 + 1]) + // Maximum of 72 byte taker signature + a sighash byte. + .push_data(&[0; 72 + 1]) .push_opcode(Opcode::OP_1) .push_opcode(Opcode::OP_0) .push_data(&redeem_script) From 7a9212396cc2cebb7fa52cfefd39d955efbd4c2e Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 8 May 2024 22:25:09 +0200 Subject: [PATCH 12/38] get tx size methods to MmCoin trait --- mm2src/coins/lp_coins.rs | 23 +++++++++++++++++++++++ mm2src/coins/utxo/utxo_common.rs | 9 +++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index eabb2193d8..94cf6e7cee 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3154,6 +3154,29 @@ pub trait MmCoin: /// Get fee to be paid by receiver per whole swap and check if the wallet has sufficient balance to pay the fee. fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; + /// Get the fee to be paid for the processing of the funding transaction. + /// Txs in success case (no refund) go as follows: + /// Chain A: funding -> taker payment -> taker payment spend (aka preimage) (to the maker & dex) + /// Chain B: maker payment -> maker payment spend (aka claimation) (to the taker) + fn get_funding_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; + + /// Get the fee to be paid for the processing of the funding-spend transaction aka taker payment transaction. + fn get_funding_spend_fee(&self, stage: FeeApproxStage) -> TradePreimageFut { + self.get_taker_payment_fee(stage) + } + + /// Get the fee to be paid for the processing of the taker payment transaction. + fn get_taker_payment_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; + + /// Get the fee to be paid for the processing of the maker payment transaction. + fn get_maker_payment_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; + + /// Get the fee to be paid for the processing of the taker payment spend transaction aka the preimage transaction. + fn get_taker_payment_spend_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; + + /// Get the fee to be paid for the processing of the maker payment spend transaction aka the claimation transaction. + fn get_maker_payment_spend_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; + /// Get transaction fee the Taker has to pay to send a `TakerFee` transaction and check if the wallet has sufficient balance to pay the fee. async fn get_fee_to_send_taker_fee( &self, diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index e8c2ce8cdb..54f4b37fbd 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -4880,12 +4880,9 @@ where T: UtxoCommonOps + GetUtxoListOps + SwapOps, { let taker_htlc_key_pair = coin.derive_htlc_key_pair(args.swap_unique_data); - // Txs in success case: - // Chain A: funding -> taker payment -> preimage (to the maker & dex) - // Chain B: maker payment -> claimation (to the taker) - // FIXME: Add taker payment fee + preimage fee - // Qs: - // 1- Who pays the maker payment fee? Take in considration that a nicer UX would be to hand the taker the full amount they requested. (so account for maker payment fee and taker claimation fee) + // FIXME: + // 1- Let the preimage tx fee be handled by the taker as well. + // 2- Who pays the maker payment fee? Take in considration that a nicer UX would be to hand the taker the full amount they requested. (so account for maker payment fee and taker claimation fee) let total_amount = &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount From 225b776715b5a059863523db5ebd61798688cc99 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 8 May 2024 23:42:40 +0200 Subject: [PATCH 13/38] get_taker_payment_spend_tx_size -> get_taker_payment_tx_size --- mm2src/coins/utxo/utxo_common.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 54f4b37fbd..b27258eeca 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -875,8 +875,8 @@ enum FundingSpendFeeSetting { UseExact(u64), } -/// Returns the taker payment spend transaction size in vbytes. -async fn get_taker_payment_spend_transaction_size(coin: &impl UtxoCommonOps) -> usize { +/// Returns the taker payment transaction size in vbytes. +async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { let preimage = TransactionInputSigner { lock_time: 0, version: coin.as_ref().conf.tx_version, From b221def890cc4e08b539103a9145e9806dd3dc16 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 9 May 2024 13:40:33 +0200 Subject: [PATCH 14/38] calculate the taker payment spend tx size as per the new protocol taker payment spend is actually taker payment here, next commit should fix the naming inconsistencies --- mm2src/coins/lp_coins.rs | 48 ++++++++++---------- mm2src/coins/test_coin.rs | 6 +++ mm2src/coins/utxo/utxo_common.rs | 4 +- mm2src/coins/utxo/utxo_standard.rs | 19 ++++++++ mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 5 +- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 2 +- 6 files changed, 55 insertions(+), 29 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 94cf6e7cee..61d9a2cffc 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1656,6 +1656,12 @@ pub trait MakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Spend maker payment transaction async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result; + + /// Get the fee to be paid for the processing of the maker payment transaction. + async fn get_maker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + + /// Get the fee to be paid for the processing of the maker payment spend transaction aka the claimation transaction. + async fn get_maker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; } #[async_trait] @@ -1856,6 +1862,25 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Derives an HTLC key-pair and returns a public key corresponding to that key. fn derive_htlc_pubkey_v2(&self, swap_unique_data: &[u8]) -> Self::Pubkey; + + /// Get the fee to be paid for the processing of the funding transaction. + /// Txs in success case (no refund) go as follows: + /// Chain A: funding -> taker payment -> taker payment spend (aka preimage) (to the maker & dex) + /// Chain B: maker payment -> maker payment spend (aka claimation) (to the taker) + async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + + /// Get the fee to be paid for the processing of the funding-spend transaction aka taker payment transaction. + /// + /// Don't use this method, use [TakerCoinSwapOpsV2::get_taker_payment_fee] instead. + async fn get_funding_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { + self.get_taker_payment_fee(stage).await + } + + /// Get the fee to be paid for the processing of the taker payment transaction. + async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + + /// Get the fee to be paid for the processing of the taker payment spend transaction aka the preimage transaction. + async fn get_taker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; } /// Operations that coins have independently from the MarketMaker. @@ -3154,29 +3179,6 @@ pub trait MmCoin: /// Get fee to be paid by receiver per whole swap and check if the wallet has sufficient balance to pay the fee. fn get_receiver_trade_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; - /// Get the fee to be paid for the processing of the funding transaction. - /// Txs in success case (no refund) go as follows: - /// Chain A: funding -> taker payment -> taker payment spend (aka preimage) (to the maker & dex) - /// Chain B: maker payment -> maker payment spend (aka claimation) (to the taker) - fn get_funding_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; - - /// Get the fee to be paid for the processing of the funding-spend transaction aka taker payment transaction. - fn get_funding_spend_fee(&self, stage: FeeApproxStage) -> TradePreimageFut { - self.get_taker_payment_fee(stage) - } - - /// Get the fee to be paid for the processing of the taker payment transaction. - fn get_taker_payment_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; - - /// Get the fee to be paid for the processing of the maker payment transaction. - fn get_maker_payment_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; - - /// Get the fee to be paid for the processing of the taker payment spend transaction aka the preimage transaction. - fn get_taker_payment_spend_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; - - /// Get the fee to be paid for the processing of the maker payment spend transaction aka the claimation transaction. - fn get_maker_payment_spend_fee(&self, stage: FeeApproxStage) -> TradePreimageFut; - /// Get transaction fee the Taker has to pay to send a `TakerFee` transaction and check if the wallet has sufficient balance to pay the fee. async fn get_fee_to_send_taker_fee( &self, diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 684edc6a29..74587ea517 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -554,4 +554,10 @@ impl TakerCoinSwapOpsV2 for TestCoin { } fn derive_htlc_pubkey_v2(&self, swap_unique_data: &[u8]) -> Self::Pubkey { todo!() } + + async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + + async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + + async fn get_taker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { todo!() } } diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index b27258eeca..cb6451b6f4 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -876,7 +876,7 @@ enum FundingSpendFeeSetting { } /// Returns the taker payment transaction size in vbytes. -async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { +pub async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { let preimage = TransactionInputSigner { lock_time: 0, version: coin.as_ref().conf.tx_version, @@ -909,7 +909,7 @@ async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { }; let redeem_script = - swap_proto_v2_scripts::taker_funding_script(0, &H160::default(), &Public::default(), &Public::default()); + swap_proto_v2_scripts::taker_funding_script(0, H160::default().as_slice(), &Public::default(), &Public::default()); let mut final_tx: UtxoTx = preimage.into(); final_tx.inputs[0].script_sig = Builder::default() diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 7137d6679b..a8dd35eb17 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -650,6 +650,10 @@ impl MakerCoinSwapOpsV2 for UtxoStandardCoin { async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result { utxo_common::spend_maker_payment_v2(self, args).await } + + async fn get_maker_payment_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + + async fn get_maker_payment_spend_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } } #[async_trait] @@ -827,6 +831,21 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { fn derive_htlc_pubkey_v2(&self, swap_unique_data: &[u8]) -> Self::Pubkey { *self.derive_htlc_key_pair(swap_unique_data).public() } + + async fn get_funding_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + + async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { + let taker_payment_tx_size = utxo_common::get_taker_payment_tx_size(self).await; + let fee_sat = self.get_htlc_spend_fee(taker_payment_tx_size as u64, stage).await?; + let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); + Ok(TradeFee { + coin: self.as_ref().conf.ticker.clone(), + amount, + paid_from_trading_vol: true, + }) + } + + async fn get_taker_payment_spend_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } } #[async_trait] diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index fcc7b70dfb..f9ed8f50ac 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -824,9 +824,8 @@ impl fee, Err(e) => { diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 1e62c97ca1..1e09e8014c 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -949,7 +949,7 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetTakerPaymentSpendFee(e.to_string()); From 481ba3e93c42d43b9c5753198b60774d7d49615c Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 9 May 2024 14:59:49 +0200 Subject: [PATCH 15/38] fix formatting --- mm2src/coins/utxo/utxo_common.rs | 8 ++++++-- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index cb6451b6f4..b4ab9ee8c4 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -908,8 +908,12 @@ pub async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { hash_algo: coin.as_ref().tx_hash_algo.into(), }; - let redeem_script = - swap_proto_v2_scripts::taker_funding_script(0, H160::default().as_slice(), &Public::default(), &Public::default()); + let redeem_script = swap_proto_v2_scripts::taker_funding_script( + 0, + H160::default().as_slice(), + &Public::default(), + &Public::default(), + ); let mut final_tx: UtxoTx = preimage.into(); final_tx.inputs[0].script_sig = Builder::default() diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index f9ed8f50ac..6faed44ba8 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -825,8 +825,7 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetTakerPaymentSpendFee(e.to_string()); From e0f649c8de7cdf14d3e76b6a6d54c45dedcfd0f9 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 10 May 2024 15:41:10 +0200 Subject: [PATCH 16/38] first batch of renamings --- mm2src/coins/lp_coins.rs | 6 +- mm2src/coins/test_coin.rs | 6 +- mm2src/coins/utxo/utxo_common.rs | 6 +- mm2src/coins/utxo/utxo_standard.rs | 12 +- mm2src/mm2_main/src/lp_ordermatch.rs | 2 +- .../src/lp_swap/komodefi.swap_v2.pb.rs | 2 +- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 4 +- mm2src/mm2_main/src/lp_swap/swap_v2.proto | 2 +- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 10 +- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 174 +++++++++--------- 10 files changed, 111 insertions(+), 113 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 61d9a2cffc..9165fa663e 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1804,21 +1804,21 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { ) -> Result>, SearchForFundingSpendErr>; /// Generates and signs a preimage spending funding tx to the combined taker payment - async fn gen_taker_funding_spend_preimage( + async fn gen_taker_payment_preimage( &self, args: &GenTakerFundingSpendArgs<'_, Self>, swap_unique_data: &[u8], ) -> GenPreimageResult; /// Validates taker funding spend preimage generated and signed by maker - async fn validate_taker_funding_spend_preimage( + async fn validate_taker_payment_preimage( &self, gen_args: &GenTakerFundingSpendArgs<'_, Self>, preimage: &TxPreimageWithSig, ) -> ValidateTakerFundingSpendPreimageResult; /// Generates and signs a preimage spending funding tx to the combined taker payment - async fn sign_and_send_taker_funding_spend( + async fn sign_and_send_taker_payment( &self, preimage: &TxPreimageWithSig, args: &GenTakerFundingSpendArgs<'_, Self>, diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 74587ea517..7b2021aecf 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -489,7 +489,7 @@ impl TakerCoinSwapOpsV2 for TestCoin { todo!() } - async fn gen_taker_funding_spend_preimage( + async fn gen_taker_payment_preimage( &self, args: &GenTakerFundingSpendArgs<'_, Self>, swap_unique_data: &[u8], @@ -497,7 +497,7 @@ impl TakerCoinSwapOpsV2 for TestCoin { todo!() } - async fn validate_taker_funding_spend_preimage( + async fn validate_taker_payment_preimage( &self, gen_args: &GenTakerFundingSpendArgs<'_, Self>, preimage: &TxPreimageWithSig, @@ -505,7 +505,7 @@ impl TakerCoinSwapOpsV2 for TestCoin { todo!() } - async fn sign_and_send_taker_funding_spend( + async fn sign_and_send_taker_payment( &self, preimage: &TxPreimageWithSig, args: &GenTakerFundingSpendArgs<'_, Self>, diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index b4ab9ee8c4..7003b1c54a 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -1098,7 +1098,7 @@ async fn gen_taker_funding_spend_preimage( .map_to_mm(TxGenError::Legacy) } -pub async fn gen_and_sign_taker_funding_spend_preimage( +pub async fn gen_and_sign_taker_payment_preimage( coin: &T, args: &GenTakerFundingSpendArgs<'_, T>, htlc_keypair: &KeyPair, @@ -1134,7 +1134,7 @@ pub async fn gen_and_sign_taker_funding_spend_preimage( /// Common implementation of taker funding spend preimage validation for UTXO coins. /// Checks maker's signature and compares received preimage with the expected tx. -pub async fn validate_taker_funding_spend_preimage( +pub async fn validate_taker_payment_preimage( coin: &T, gen_args: &GenTakerFundingSpendArgs<'_, T>, preimage: &TxPreimageWithSig, @@ -1213,7 +1213,7 @@ pub async fn validate_taker_funding_spend_preimage( } /// Common implementation of taker funding spend finalization and broadcast for UTXO coins. -pub async fn sign_and_send_taker_funding_spend( +pub async fn sign_and_send_taker_payment( coin: &T, preimage: &TxPreimageWithSig, gen_args: &GenTakerFundingSpendArgs<'_, T>, diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index a8dd35eb17..8f1d380a81 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -751,31 +751,31 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { } } - async fn gen_taker_funding_spend_preimage( + async fn gen_taker_payment_preimage( &self, args: &GenTakerFundingSpendArgs<'_, Self>, swap_unique_data: &[u8], ) -> GenPreimageResult { let htlc_keypair = self.derive_htlc_key_pair(swap_unique_data); - utxo_common::gen_and_sign_taker_funding_spend_preimage(self, args, &htlc_keypair).await + utxo_common::gen_and_sign_taker_payment_preimage(self, args, &htlc_keypair).await } - async fn validate_taker_funding_spend_preimage( + async fn validate_taker_payment_preimage( &self, gen_args: &GenTakerFundingSpendArgs<'_, Self>, preimage: &TxPreimageWithSig, ) -> ValidateTakerFundingSpendPreimageResult { - utxo_common::validate_taker_funding_spend_preimage(self, gen_args, preimage).await + utxo_common::validate_taker_payment_preimage(self, gen_args, preimage).await } - async fn sign_and_send_taker_funding_spend( + async fn sign_and_send_taker_payment( &self, preimage: &TxPreimageWithSig, args: &GenTakerFundingSpendArgs<'_, Self>, swap_unique_data: &[u8], ) -> Result { let htlc_keypair = self.derive_htlc_key_pair(swap_unique_data); - utxo_common::sign_and_send_taker_funding_spend(self, preimage, args, &htlc_keypair).await + utxo_common::sign_and_send_taker_payment(self, preimage, args, &htlc_keypair).await } async fn refund_combined_taker_payment(&self, args: RefundPaymentArgs<'_>) -> Result { diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index c2b2d44d0f..67db9936f5 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -3156,7 +3156,7 @@ fn lp_connected_alice(ctx: MmArc, taker_order: TakerOrder, taker_match: TakerMat maker_p2p_pubkey: match maker_p2p_pubkey { PublicKey::Secp256k1(pubkey) => pubkey.into(), }, - require_maker_payment_confirm_before_funding_spend: true, + require_maker_payment_confirm_before_taker_payment: true, }; #[allow(clippy::box_default)] taker_swap_state_machine diff --git a/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs b/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs index da06b76b20..b3a1de28e2 100644 --- a/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs +++ b/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs @@ -54,7 +54,7 @@ pub struct TakerNegotiationData { #[prost(bytes = "vec", optional, tag = "8")] pub taker_coin_swap_contract: ::core::option::Option<::prost::alloc::vec::Vec>, #[prost(uint64, tag = "9")] - pub taker_payment_spend_fee: u64, + pub taker_payment_fee: u64, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 6faed44ba8..c6c87136de 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -972,7 +972,7 @@ impl p, diff --git a/mm2src/mm2_main/src/lp_swap/swap_v2.proto b/mm2src/mm2_main/src/lp_swap/swap_v2.proto index a13958df66..a1475c0218 100644 --- a/mm2src/mm2_main/src/lp_swap/swap_v2.proto +++ b/mm2src/mm2_main/src/lp_swap/swap_v2.proto @@ -32,7 +32,7 @@ message TakerNegotiationData { bytes taker_coin_htlc_pub = 6; optional bytes maker_coin_swap_contract = 7; optional bytes taker_coin_swap_contract = 8; - uint64 taker_payment_spend_fee = 9; + uint64 taker_payment_fee = 9; } message TakerNegotiation { diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 2114a63691..a2eb9cb9fa 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1031,7 +1031,7 @@ impl TakerSwap { let params = TakerSwapPreparedParams { dex_fee: dex_fee.total_spend_amount(), fee_to_send_dex_fee: fee_to_send_dex_fee.clone(), - taker_payment_trade_fee: taker_payment_trade_fee.clone(), + funding_fee: taker_payment_trade_fee.clone(), maker_payment_spend_trade_fee: maker_payment_spend_trade_fee.clone(), }; let check_balance_f = check_balance_for_taker_swap( @@ -2359,7 +2359,7 @@ impl AtomicSwap for TakerSwap { pub struct TakerSwapPreparedParams { pub(super) dex_fee: MmNumber, pub(super) fee_to_send_dex_fee: TradeFee, - pub(super) taker_payment_trade_fee: TradeFee, + pub(super) funding_fee: TradeFee, pub(super) maker_payment_spend_trade_fee: TradeFee, } @@ -2393,7 +2393,7 @@ pub async fn check_balance_for_taker_swap( TakerSwapPreparedParams { dex_fee: dex_fee.total_spend_amount(), fee_to_send_dex_fee, - taker_payment_trade_fee, + funding_fee: taker_payment_trade_fee, maker_payment_spend_trade_fee, } }, @@ -2409,7 +2409,7 @@ pub async fn check_balance_for_taker_swap( my_coin, swap_uuid, volume, - params.taker_payment_trade_fee, + params.funding_fee, Some(taker_fee), ) .await?; @@ -2489,7 +2489,7 @@ pub async fn taker_swap_trade_preimage( let prepared_params = TakerSwapPreparedParams { dex_fee: dex_amount.total_spend_amount(), fee_to_send_dex_fee: fee_to_send_taker_fee.clone(), - taker_payment_trade_fee: my_coin_trade_fee.clone(), + funding_fee: my_coin_trade_fee.clone(), maker_payment_spend_trade_fee: other_coin_trade_fee.clone(), }; check_balance_for_taker_swap( diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 1e09e8014c..374480da5c 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -67,8 +67,8 @@ pub enum TakerSwapEvent { Initialized { maker_coin_start_block: u64, taker_coin_start_block: u64, + funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - taker_payment_spend_fee: SavedTradeFee, maker_payment_spend_fee: SavedTradeFee, }, /// Negotiated swap data with maker. @@ -76,8 +76,8 @@ pub enum TakerSwapEvent { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: StoredNegotiationData, + funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - taker_payment_spend_fee: SavedTradeFee, maker_payment_spend_fee: SavedTradeFee, }, /// Sent taker funding tx. @@ -86,7 +86,7 @@ pub enum TakerSwapEvent { taker_coin_start_block: u64, negotiation_data: StoredNegotiationData, taker_funding: TransactionIdentifier, - taker_payment_spend_fee: SavedTradeFee, + taker_payment_fee: SavedTradeFee, }, /// Taker funding tx refund is required. TakerFundingRefundRequired { @@ -97,13 +97,13 @@ pub enum TakerSwapEvent { reason: TakerFundingRefundReason, }, /// Received maker payment and taker funding spend preimage - MakerPaymentAndFundingSpendPreimgReceived { + MakerPaymentAndTakerPaymentPreimageReceived { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: StoredNegotiationData, - taker_payment_spend_fee: SavedTradeFee, + taker_payment_fee: SavedTradeFee, taker_funding: TransactionIdentifier, - funding_spend_preimage: StoredTxPreimage, + taker_payment_preimage: StoredTxPreimage, maker_payment: TransactionIdentifier, }, /// Sent taker payment. @@ -126,7 +126,7 @@ pub enum TakerSwapEvent { taker_coin_start_block: u64, maker_payment: TransactionIdentifier, taker_funding: TransactionIdentifier, - funding_spend_preimage: StoredTxPreimage, + taker_payment_preimage: StoredTxPreimage, negotiation_data: StoredNegotiationData, }, /// Maker spent taker's payment and taker discovered the tx on-chain. @@ -423,7 +423,7 @@ pub struct TakerSwapStateMachine @@ -498,24 +498,24 @@ impl Box::new(Initialized { maker_coin: Default::default(), taker_coin: Default::default(), maker_coin_start_block, taker_coin_start_block, + funding_fee, taker_payment_fee, - taker_payment_spend_fee, maker_payment_spend_fee, }), TakerSwapEvent::Negotiated { maker_coin_start_block, taker_coin_start_block, negotiation_data, + funding_fee, taker_payment_fee, - taker_payment_spend_fee, maker_payment_spend_fee, } => Box::new(Negotiated { maker_coin_start_block, @@ -525,8 +525,8 @@ impl Box::new(TakerFundingSent { maker_coin_start_block, taker_coin_start_block, @@ -547,7 +547,7 @@ impl Box::new(MakerPaymentAndFundingSpendPreimgReceived { + taker_payment_preimage, + } => Box::new(MakerPaymentAndTakerPaymentPreimageReceived { maker_coin_start_block, taker_coin_start_block, negotiation_data: NegotiationData::from_stored_data( @@ -585,19 +585,19 @@ impl Box::new(MakerPaymentConfirmed { maker_coin_start_block, @@ -662,14 +662,14 @@ impl { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); @@ -818,8 +818,8 @@ impl { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); @@ -874,8 +874,8 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetTakerPaymentSpendFee(e.to_string()); @@ -959,11 +960,10 @@ impl { taker_coin: PhantomData, maker_coin_start_block: u64, taker_coin_start_block: u64, + funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - taker_payment_spend_fee: SavedTradeFee, maker_payment_spend_fee: SavedTradeFee, } @@ -1051,8 +1051,8 @@ impl, + funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - taker_payment_spend_fee: SavedTradeFee, maker_payment_spend_fee: SavedTradeFee, } @@ -1280,7 +1277,7 @@ impl, - taker_payment_spend_fee: SavedTradeFee, + taker_payment_fee: SavedTradeFee, } #[async_trait] @@ -1435,13 +1432,13 @@ impl { +struct MakerPaymentAndTakerPaymentPreimageReceived { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, - taker_payment_spend_fee: SavedTradeFee, + taker_payment_fee: SavedTradeFee, taker_funding: TakerCoin::Tx, - funding_spend_preimage: TxPreimageWithSig, + taker_payment_preimage: TxPreimageWithSig, maker_payment: MakerCoin::Tx, } impl TransitionFrom> - for MakerPaymentAndFundingSpendPreimgReceived + for MakerPaymentAndTakerPaymentPreimageReceived { } impl StorableState - for MakerPaymentAndFundingSpendPreimgReceived + for MakerPaymentAndTakerPaymentPreimageReceived { type StateMachine = TakerSwapStateMachine; fn get_event(&self) -> TakerSwapEvent { - TakerSwapEvent::MakerPaymentAndFundingSpendPreimgReceived { + TakerSwapEvent::MakerPaymentAndTakerPaymentPreimageReceived { maker_coin_start_block: self.maker_coin_start_block, taker_coin_start_block: self.taker_coin_start_block, negotiation_data: self.negotiation_data.to_stored_data(), - taker_payment_spend_fee: self.taker_payment_spend_fee.clone(), + taker_payment_fee: self.taker_payment_fee.clone(), taker_funding: TransactionIdentifier { tx_hex: self.taker_funding.tx_hex().into(), tx_hash: self.taker_funding.tx_hash(), }, - funding_spend_preimage: StoredTxPreimage { - preimage: self.funding_spend_preimage.preimage.to_bytes().into(), - signature: self.funding_spend_preimage.signature.to_bytes().into(), + taker_payment_preimage: StoredTxPreimage { + preimage: self.taker_payment_preimage.preimage.to_bytes().into(), + signature: self.taker_payment_preimage.signature.to_bytes().into(), }, maker_payment: TransactionIdentifier { tx_hex: self.maker_payment.tx_hex().into(), @@ -1520,7 +1517,7 @@ impl State - for MakerPaymentAndFundingSpendPreimgReceived + for MakerPaymentAndTakerPaymentPreimageReceived { type StateMachine = TakerSwapStateMachine; @@ -1556,12 +1553,12 @@ impl tx, @@ -1667,10 +1664,8 @@ impl { } -// FIXME: We should use consistent namings. FundingSpendPreimage is a partially signed TakerPayment. -// We should either call FundingSpendPreimage -> TakerPaymentPreimage or we call TakerPayment -> FundingSpend. impl - TransitionFrom> + TransitionFrom> for TakerPaymentSent { } @@ -1682,7 +1677,10 @@ impl; async fn on_changed(self: Box, state_machine: &mut Self::StateMachine) -> StateResult { - if !state_machine.require_maker_payment_confirm_before_funding_spend { + // FIXME: This variable were used before to wait before signing and sending the taker payment. + // Why is it used again to wait before sending the taker payment spend. Waiting should be the + // correct action and not based on that variable (as per the protocol). + if !state_machine.require_maker_payment_confirm_before_taker_payment { let input = ConfirmPaymentInput { payment_tx: self.maker_payment.tx_hex(), confirmations: state_machine.conf_settings.maker_coin_confs, @@ -1835,7 +1833,7 @@ impl { } impl - TransitionFrom> + TransitionFrom> for TakerFundingRefundRequired { } @@ -2012,12 +2010,12 @@ struct MakerPaymentConfirmed, + taker_payment_preimage: TxPreimageWithSig, negotiation_data: NegotiationData, } impl - TransitionFrom> + TransitionFrom> for MakerPaymentConfirmed { } @@ -2044,7 +2042,7 @@ impl tx, @@ -2096,9 +2094,9 @@ impl Date: Fri, 10 May 2024 15:43:45 +0200 Subject: [PATCH 17/38] always wait for maker payment before proceeding with taker payment spent don't depend on no variable on this regard --- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 33 +++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 374480da5c..a5e87a14d9 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -1677,26 +1677,21 @@ impl; async fn on_changed(self: Box, state_machine: &mut Self::StateMachine) -> StateResult { - // FIXME: This variable were used before to wait before signing and sending the taker payment. - // Why is it used again to wait before sending the taker payment spend. Waiting should be the - // correct action and not based on that variable (as per the protocol). - if !state_machine.require_maker_payment_confirm_before_taker_payment { - let input = ConfirmPaymentInput { - payment_tx: self.maker_payment.tx_hex(), - confirmations: state_machine.conf_settings.maker_coin_confs, - requires_nota: state_machine.conf_settings.maker_coin_nota, - wait_until: state_machine.maker_payment_conf_timeout(), - check_every: 10, - }; + let input = ConfirmPaymentInput { + payment_tx: self.maker_payment.tx_hex(), + confirmations: state_machine.conf_settings.maker_coin_confs, + requires_nota: state_machine.conf_settings.maker_coin_nota, + wait_until: state_machine.maker_payment_conf_timeout(), + check_every: 10, + }; - if let Err(e) = state_machine.maker_coin.wait_for_confirmations(input).compat().await { - let next_state = TakerPaymentRefundRequired { - taker_payment: self.taker_payment, - negotiation_data: self.negotiation_data, - reason: TakerPaymentRefundReason::MakerPaymentNotConfirmedInTime(e), - }; - return Self::change_state(next_state, state_machine).await; - } + if let Err(e) = state_machine.maker_coin.wait_for_confirmations(input).compat().await { + let next_state = TakerPaymentRefundRequired { + taker_payment: self.taker_payment, + negotiation_data: self.negotiation_data, + reason: TakerPaymentRefundReason::MakerPaymentNotConfirmedInTime(e), + }; + return Self::change_state(next_state, state_machine).await; } let unique_data = state_machine.unique_data(); From d90ad0eba7586d286eb04aef180e06f87814a7d6 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 10 May 2024 16:09:14 +0200 Subject: [PATCH 18/38] stop un-needed propagation of `maker_payment_spend_fee` --- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index a5e87a14d9..95b58eefdd 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -69,7 +69,6 @@ pub enum TakerSwapEvent { taker_coin_start_block: u64, funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - maker_payment_spend_fee: SavedTradeFee, }, /// Negotiated swap data with maker. Negotiated { @@ -78,7 +77,6 @@ pub enum TakerSwapEvent { negotiation_data: StoredNegotiationData, funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - maker_payment_spend_fee: SavedTradeFee, }, /// Sent taker funding tx. TakerFundingSent { @@ -500,7 +498,6 @@ impl Box::new(Initialized { maker_coin: Default::default(), taker_coin: Default::default(), @@ -508,7 +505,6 @@ impl Box::new(Negotiated { maker_coin_start_block, taker_coin_start_block, @@ -527,7 +522,6 @@ impl { taker_coin_start_block: u64, funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - maker_payment_spend_fee: SavedTradeFee, } impl TransitionFrom> for Initialized {} @@ -1053,7 +1042,6 @@ impl, funding_fee: SavedTradeFee, taker_payment_fee: SavedTradeFee, - maker_payment_spend_fee: SavedTradeFee, } impl TransitionFrom> @@ -1321,7 +1307,6 @@ impl Date: Fri, 10 May 2024 19:56:49 +0200 Subject: [PATCH 19/38] more consistent renaming on maker side --- mm2src/coins/lp_coins.rs | 12 +- mm2src/coins/test_coin.rs | 8 +- mm2src/coins/utxo/utxo_common.rs | 16 +- mm2src/coins/utxo/utxo_standard.rs | 8 +- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 8 +- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 155 +++++++++---------- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 18 +-- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 40 ++--- 8 files changed, 132 insertions(+), 133 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 9165fa663e..d69b506647 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1259,7 +1259,7 @@ pub struct RefundFundingSecretArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { } /// Helper struct wrapping arguments for [TakerCoinSwapOpsV2::gen_taker_funding_spend_preimage] -pub struct GenTakerFundingSpendArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { +pub struct GenTakerPaymentPreimageArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Taker payment transaction serialized to raw bytes pub funding_tx: &'a Coin::Tx, /// Maker's pubkey @@ -1275,7 +1275,7 @@ pub struct GenTakerFundingSpendArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// The hash of the secret generated by maker pub maker_secret_hash: &'a [u8], /// The extra fee added to the trading volume to cover the taker payment spend transaction fees - pub taker_payment_spend_fee: BigDecimal, + pub taker_payment_fee: BigDecimal, } /// Helper struct wrapping arguments for [TakerCoinSwapOpsV2::validate_taker_funding] @@ -1291,7 +1291,7 @@ pub struct ValidateTakerFundingArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// DEX fee amount pub dex_fee: &'a DexFee, /// The extra fee added to the trading volume to cover the taker payment spend transaction fees - pub taker_payment_spend_fee: BigDecimal, + pub taker_payment_fee: BigDecimal, /// Additional reward for maker (premium) pub premium_amount: BigDecimal, /// Actual volume of taker's payment @@ -1806,14 +1806,14 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Generates and signs a preimage spending funding tx to the combined taker payment async fn gen_taker_payment_preimage( &self, - args: &GenTakerFundingSpendArgs<'_, Self>, + args: &GenTakerPaymentPreimageArgs<'_, Self>, swap_unique_data: &[u8], ) -> GenPreimageResult; /// Validates taker funding spend preimage generated and signed by maker async fn validate_taker_payment_preimage( &self, - gen_args: &GenTakerFundingSpendArgs<'_, Self>, + gen_args: &GenTakerPaymentPreimageArgs<'_, Self>, preimage: &TxPreimageWithSig, ) -> ValidateTakerFundingSpendPreimageResult; @@ -1821,7 +1821,7 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { async fn sign_and_send_taker_payment( &self, preimage: &TxPreimageWithSig, - args: &GenTakerFundingSpendArgs<'_, Self>, + args: &GenTakerPaymentPreimageArgs<'_, Self>, swap_unique_data: &[u8], ) -> Result; diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 7b2021aecf..a383c85680 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -5,7 +5,7 @@ use super::{CoinBalance, FundingTxSpend, HistorySyncState, MarketCoinOps, MmCoin WaitForTakerPaymentSpendError}; use crate::coin_errors::ValidatePaymentResult; use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinFutSpawner, - ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, GenPreimageResult, GenTakerFundingSpendArgs, + ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, GenPreimageResult, GenTakerPaymentPreimageArgs, GenTakerPaymentSpendArgs, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr, ParseCoinAssocTypes, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, RawTransactionResult, RefundFundingSecretArgs, RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput, @@ -491,7 +491,7 @@ impl TakerCoinSwapOpsV2 for TestCoin { async fn gen_taker_payment_preimage( &self, - args: &GenTakerFundingSpendArgs<'_, Self>, + args: &GenTakerPaymentPreimageArgs<'_, Self>, swap_unique_data: &[u8], ) -> GenPreimageResult { todo!() @@ -499,7 +499,7 @@ impl TakerCoinSwapOpsV2 for TestCoin { async fn validate_taker_payment_preimage( &self, - gen_args: &GenTakerFundingSpendArgs<'_, Self>, + gen_args: &GenTakerPaymentPreimageArgs<'_, Self>, preimage: &TxPreimageWithSig, ) -> ValidateTakerFundingSpendPreimageResult { todo!() @@ -508,7 +508,7 @@ impl TakerCoinSwapOpsV2 for TestCoin { async fn sign_and_send_taker_payment( &self, preimage: &TxPreimageWithSig, - args: &GenTakerFundingSpendArgs<'_, Self>, + args: &GenTakerPaymentPreimageArgs<'_, Self>, swap_unique_data: &[u8], ) -> Result { todo!() diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 7003b1c54a..330164fa3a 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -13,7 +13,7 @@ use crate::utxo::utxo_hd_wallet::UtxoHDAddress; use crate::utxo::utxo_withdraw::{InitUtxoWithdraw, StandardUtxoWithdraw, UtxoWithdraw}; use crate::watcher_common::validate_watcher_reward; use crate::{scan_for_new_addresses_impl, CanRefundHtlc, CoinBalance, CoinWithDerivationMethod, ConfirmPaymentInput, - DexFee, GenPreimageResult, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, GetWithdrawSenderAddress, + DexFee, GenPreimageResult, GenTakerPaymentPreimageArgs, GenTakerPaymentSpendArgs, GetWithdrawSenderAddress, RawTransactionError, RawTransactionRequest, RawTransactionRes, RawTransactionResult, RefundFundingSecretArgs, RefundMakerPaymentArgs, RefundPaymentArgs, RewardTarget, SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, @@ -1034,7 +1034,7 @@ type GenPreimageResInner = MmResult; async fn gen_taker_funding_spend_preimage( coin: &T, - args: &GenTakerFundingSpendArgs<'_, T>, + args: &GenTakerPaymentPreimageArgs<'_, T>, n_time: NTimeSetting, fee: FundingSpendFeeSetting, ) -> GenPreimageResInner { @@ -1062,7 +1062,7 @@ async fn gen_taker_funding_spend_preimage( .get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE, &FeeApproxStage::WithoutApprox) .await?; let taker_instructed_fee = - sat_from_big_decimal(&args.taker_payment_spend_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; + sat_from_big_decimal(&args.taker_payment_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; // If calculated fee is less than instructed fee, use instructed fee because it was never intended // to be deposited to us (maker). If the calculated fee is larger, we will incur the fee difference // just to make sure the transaction is confirmed quickly. @@ -1100,7 +1100,7 @@ async fn gen_taker_funding_spend_preimage( pub async fn gen_and_sign_taker_payment_preimage( coin: &T, - args: &GenTakerFundingSpendArgs<'_, T>, + args: &GenTakerPaymentPreimageArgs<'_, T>, htlc_keypair: &KeyPair, ) -> GenPreimageResult { let funding_time_lock = args @@ -1136,7 +1136,7 @@ pub async fn gen_and_sign_taker_payment_preimage( /// Checks maker's signature and compares received preimage with the expected tx. pub async fn validate_taker_payment_preimage( coin: &T, - gen_args: &GenTakerFundingSpendArgs<'_, T>, + gen_args: &GenTakerPaymentPreimageArgs<'_, T>, preimage: &TxPreimageWithSig, ) -> ValidateTakerFundingSpendPreimageResult { let funding_amount = gen_args @@ -1160,7 +1160,7 @@ pub async fn validate_taker_payment_preimage( let actual_fee = funding_amount - payment_amount; let instructed_fee = - sat_from_big_decimal(&gen_args.taker_payment_spend_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; + sat_from_big_decimal(&gen_args.taker_payment_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; if actual_fee < instructed_fee { return MmError::err(ValidateTakerFundingSpendPreimageError::UnexpectedPreimageFee(format!( @@ -1216,7 +1216,7 @@ pub async fn validate_taker_payment_preimage( pub async fn sign_and_send_taker_payment( coin: &T, preimage: &TxPreimageWithSig, - gen_args: &GenTakerFundingSpendArgs<'_, T>, + gen_args: &GenTakerPaymentPreimageArgs<'_, T>, htlc_keypair: &KeyPair, ) -> Result { let redeem_script = swap_proto_v2_scripts::taker_funding_script( @@ -4985,7 +4985,7 @@ where let total_expected_amount = &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount - + &args.taker_payment_spend_fee; + + &args.taker_payment_fee; let expected_amount_sat = sat_from_big_decimal(&total_expected_amount, coin.as_ref().decimals)?; diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 8f1d380a81..e0d7a96099 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -22,7 +22,7 @@ use crate::utxo::utxo_builder::{UtxoArcBuilder, UtxoCoinBuilder}; use crate::utxo::utxo_tx_history_v2::{UtxoMyAddressesHistoryError, UtxoTxDetailsError, UtxoTxDetailsParams, UtxoTxHistoryOps}; use crate::{CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinBalance, CoinWithDerivationMethod, CoinWithPrivKeyPolicy, - ConfirmPaymentInput, DexFee, FundingTxSpend, GenPreimageResult, GenTakerFundingSpendArgs, + ConfirmPaymentInput, DexFee, FundingTxSpend, GenPreimageResult, GenTakerPaymentPreimageArgs, GenTakerPaymentSpendArgs, GetWithdrawSenderAddress, IguanaBalanceOps, IguanaPrivKey, MakerCoinSwapOpsV2, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, PrivKeyBuildPolicy, RawTransactionRequest, RawTransactionResult, RefundError, @@ -753,7 +753,7 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { async fn gen_taker_payment_preimage( &self, - args: &GenTakerFundingSpendArgs<'_, Self>, + args: &GenTakerPaymentPreimageArgs<'_, Self>, swap_unique_data: &[u8], ) -> GenPreimageResult { let htlc_keypair = self.derive_htlc_key_pair(swap_unique_data); @@ -762,7 +762,7 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { async fn validate_taker_payment_preimage( &self, - gen_args: &GenTakerFundingSpendArgs<'_, Self>, + gen_args: &GenTakerPaymentPreimageArgs<'_, Self>, preimage: &TxPreimageWithSig, ) -> ValidateTakerFundingSpendPreimageResult { utxo_common::validate_taker_payment_preimage(self, gen_args, preimage).await @@ -771,7 +771,7 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { async fn sign_and_send_taker_payment( &self, preimage: &TxPreimageWithSig, - args: &GenTakerFundingSpendArgs<'_, Self>, + args: &GenTakerPaymentPreimageArgs<'_, Self>, swap_unique_data: &[u8], ) -> Result { let htlc_keypair = self.derive_htlc_key_pair(swap_unique_data); diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 27b5bedd0e..a9e7407d6b 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -495,7 +495,7 @@ impl MakerSwap { let params = MakerSwapPreparedParams { maker_payment_trade_fee: maker_payment_trade_fee.clone(), - taker_payment_spend_trade_fee: taker_payment_spend_trade_fee.clone(), + taker_payment_fee: taker_payment_spend_trade_fee.clone(), }; match check_balance_for_maker_swap( &self.ctx, @@ -2161,7 +2161,7 @@ pub async fn run_maker_swap(swap: RunMakerSwapInput, ctx: MmArc) { pub struct MakerSwapPreparedParams { pub(super) maker_payment_trade_fee: TradeFee, - pub(super) taker_payment_spend_trade_fee: TradeFee, + pub(super) taker_payment_fee: TradeFee, } pub async fn check_balance_for_maker_swap( @@ -2176,7 +2176,7 @@ pub async fn check_balance_for_maker_swap( let (maker_payment_trade_fee, taker_payment_spend_trade_fee) = match prepared_params { Some(MakerSwapPreparedParams { maker_payment_trade_fee, - taker_payment_spend_trade_fee, + taker_payment_fee: taker_payment_spend_trade_fee, }) => (maker_payment_trade_fee, taker_payment_spend_trade_fee), None => { let preimage_value = TradePreimageValue::Exact(volume.to_decimal()); @@ -2251,7 +2251,7 @@ pub async fn maker_swap_trade_preimage( } else { let prepared_params = MakerSwapPreparedParams { maker_payment_trade_fee: base_coin_fee.clone(), - taker_payment_spend_trade_fee: rel_coin_fee.clone(), + taker_payment_fee: rel_coin_fee.clone(), }; check_balance_for_maker_swap( ctx, diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index c6c87136de..43ddc0a74f 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -9,7 +9,7 @@ use crate::mm2::lp_swap::{broadcast_swap_v2_msg_every, check_balance_for_maker_s use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use coins::utxo::utxo_common::big_decimal_from_sat_unsigned; -use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, FundingTxSpend, GenTakerFundingSpendArgs, +use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, FundingTxSpend, GenTakerPaymentPreimageArgs, GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, ParseCoinAssocTypes, RefundMakerPaymentArgs, RefundPaymentArgs, SearchForFundingSpendErr, SendMakerPaymentArgs, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, TradePreimageValue, Transaction, TxPreimageWithSig, ValidateTakerFundingArgs}; @@ -56,7 +56,7 @@ pub struct StoredNegotiationData { maker_coin_swap_contract: Option, taker_coin_swap_contract: Option, taker_secret_hash: BytesJson, - taker_payment_spend_fee: BigDecimal, + taker_payment_fee: BigDecimal, } /// Represents events produced by maker swap states. @@ -67,15 +67,15 @@ pub enum MakerSwapEvent { Initialized { maker_coin_start_block: u64, taker_coin_start_block: u64, - maker_payment_trade_fee: SavedTradeFee, - taker_payment_spend_trade_fee: SavedTradeFee, + maker_payment_fee: SavedTradeFee, + taker_payment_fee: SavedTradeFee, }, /// Started waiting for taker funding tx. WaitingForTakerFunding { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: StoredNegotiationData, - maker_payment_trade_fee: SavedTradeFee, + maker_payment_fee: SavedTradeFee, }, /// Received taker funding info. TakerFundingReceived { @@ -83,16 +83,16 @@ pub enum MakerSwapEvent { taker_coin_start_block: u64, negotiation_data: StoredNegotiationData, taker_funding: TransactionIdentifier, - maker_payment_trade_fee: SavedTradeFee, + maker_payment_fee: SavedTradeFee, }, - /// Sent maker payment and generated funding spend preimage. - MakerPaymentSentFundingSpendGenerated { + /// Sent maker payment and generated taker payment preimage. + MakerPaymentSentTakerPaymentPreimageGenerated { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: StoredNegotiationData, maker_payment: TransactionIdentifier, taker_funding: TransactionIdentifier, - funding_spend_preimage: StoredTxPreimage, + taker_payment_preimage: StoredTxPreimage, }, /// Something went wrong, so maker payment refund is required. MakerPaymentRefundRequired { @@ -465,21 +465,21 @@ impl Box::new(Initialized { maker_coin: Default::default(), taker_coin: Default::default(), maker_coin_start_block, taker_coin_start_block, - maker_payment_trade_fee, - taker_payment_spend_trade_fee, + maker_payment_fee, + taker_payment_fee, }), MakerSwapEvent::WaitingForTakerFunding { maker_coin_start_block, taker_coin_start_block, negotiation_data, - maker_payment_trade_fee, + maker_payment_fee, } => Box::new(WaitingForTakerFunding { maker_coin_start_block, taker_coin_start_block, @@ -488,14 +488,14 @@ impl Box::new(TakerFundingReceived { maker_coin_start_block, taker_coin_start_block, @@ -508,16 +508,16 @@ impl Box::new(MakerPaymentSentFundingSpendGenerated { + taker_payment_preimage, + } => Box::new(MakerPaymentSentTakerPaymentPreimageGenerated { maker_coin_start_block, taker_coin_start_block, negotiation_data: NegotiationData::from_stored_data( @@ -529,14 +529,14 @@ impl { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); @@ -691,7 +690,7 @@ impl { + MakerSwapEvent::MakerPaymentSentTakerPaymentPreimageGenerated { .. } => { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); let ticker = self.maker_coin.ticker(); if let Some(maker_coin_locked) = swaps_ctx.locked_amounts.lock().unwrap().get_mut(ticker) { @@ -726,15 +725,15 @@ impl { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); @@ -744,7 +743,7 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetTakerPaymentSpendFee(e.to_string()); @@ -834,8 +833,8 @@ impl { taker_coin: PhantomData, maker_coin_start_block: u64, taker_coin_start_block: u64, - maker_payment_trade_fee: SavedTradeFee, - taker_payment_spend_trade_fee: SavedTradeFee, + maker_payment_fee: SavedTradeFee, + taker_payment_fee: SavedTradeFee, } impl TransitionFrom> for Initialized {} @@ -886,8 +885,8 @@ impl>, taker_coin_swap_contract: Option>, taker_secret_hash: Vec, - taker_payment_spend_fee: BigDecimal, + taker_payment_fee: BigDecimal, } impl NegotiationData { @@ -1045,7 +1044,7 @@ impl Negotiation maker_coin_swap_contract: self.maker_coin_swap_contract.clone().map(|b| b.into()), taker_coin_swap_contract: self.taker_coin_swap_contract.clone().map(|b| b.into()), taker_secret_hash: self.taker_secret_hash.clone().into(), - taker_payment_spend_fee: self.taker_payment_spend_fee.clone(), + taker_payment_fee: self.taker_payment_fee.clone(), } } @@ -1066,7 +1065,7 @@ impl Negotiation maker_coin_swap_contract: None, taker_coin_swap_contract: None, taker_secret_hash: stored.taker_secret_hash.into(), - taker_payment_spend_fee: stored.taker_payment_spend_fee, + taker_payment_fee: stored.taker_payment_fee, }) } } @@ -1075,7 +1074,7 @@ struct WaitingForTakerFunding, - maker_payment_trade_fee: SavedTradeFee, + maker_payment_fee: SavedTradeFee, } impl TransitionFrom> @@ -1135,7 +1134,7 @@ impl, taker_funding: TakerCoin::Tx, - maker_payment_trade_fee: SavedTradeFee, + maker_payment_fee: SavedTradeFee, } impl @@ -1184,7 +1183,7 @@ impl p, Err(e) => { - let reason = AbortReason::FailedToGenerateFundingSpend(e.to_string()); + let reason = AbortReason::FailedToGenerateTakerPaymentPreimage(e.to_string()); return Self::change_state(Aborted::new(reason), state_machine).await; }, }; @@ -1238,12 +1237,12 @@ impl { +struct MakerPaymentSentTakerPaymentPreimageGenerated { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, taker_funding: TakerCoin::Tx, - funding_spend_preimage: TxPreimageWithSig, + taker_payment_preimage: TxPreimageWithSig, maker_payment: MakerCoin::Tx, } impl TransitionFrom> - for MakerPaymentSentFundingSpendGenerated + for MakerPaymentSentTakerPaymentPreimageGenerated { } #[async_trait] impl State - for MakerPaymentSentFundingSpendGenerated + for MakerPaymentSentTakerPaymentPreimageGenerated { type StateMachine = MakerSwapStateMachine; @@ -1295,8 +1294,8 @@ impl StorableState - for MakerPaymentSentFundingSpendGenerated + for MakerPaymentSentTakerPaymentPreimageGenerated { type StateMachine = MakerSwapStateMachine; fn get_event(&self) -> MakerSwapEvent { - MakerSwapEvent::MakerPaymentSentFundingSpendGenerated { + MakerSwapEvent::MakerPaymentSentTakerPaymentPreimageGenerated { maker_coin_start_block: self.maker_coin_start_block, taker_coin_start_block: self.taker_coin_start_block, negotiation_data: self.negotiation_data.to_stored_data(), @@ -1416,9 +1415,9 @@ impl - TransitionFrom> + TransitionFrom> for MakerPaymentRefundRequired { } @@ -1583,7 +1582,7 @@ struct TakerPaymentReceived - TransitionFrom> + TransitionFrom> for TakerPaymentReceived { } @@ -1815,7 +1814,7 @@ pub enum AbortReason { DidNotReceiveTakerFundingInfo(String), FailedToParseTakerFunding(String), TakerFundingValidationFailed(String), - FailedToGenerateFundingSpend(String), + FailedToGenerateTakerPaymentPreimage(String), FailedToSendMakerPayment(String), TooLargeStartedAtDiff(u64), TakerProvidedInvalidFundingLocktime(u64), diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index a2eb9cb9fa..b2d258441b 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1032,7 +1032,7 @@ impl TakerSwap { dex_fee: dex_fee.total_spend_amount(), fee_to_send_dex_fee: fee_to_send_dex_fee.clone(), funding_fee: taker_payment_trade_fee.clone(), - maker_payment_spend_trade_fee: maker_payment_spend_trade_fee.clone(), + maker_payment_spend_fee: maker_payment_spend_trade_fee.clone(), }; let check_balance_f = check_balance_for_taker_swap( &self.ctx, @@ -2360,7 +2360,7 @@ pub struct TakerSwapPreparedParams { pub(super) dex_fee: MmNumber, pub(super) fee_to_send_dex_fee: TradeFee, pub(super) funding_fee: TradeFee, - pub(super) maker_payment_spend_trade_fee: TradeFee, + pub(super) maker_payment_spend_fee: TradeFee, } pub async fn check_balance_for_taker_swap( @@ -2381,11 +2381,11 @@ pub async fn check_balance_for_taker_swap( .await .mm_err(|e| CheckBalanceError::from_trade_preimage_error(e, my_coin.ticker()))?; let preimage_value = TradePreimageValue::Exact(volume.to_decimal()); - let taker_payment_trade_fee = my_coin + let funding_fee = my_coin .get_sender_trade_fee(preimage_value, stage) .await .mm_err(|e| CheckBalanceError::from_trade_preimage_error(e, my_coin.ticker()))?; - let maker_payment_spend_trade_fee = other_coin + let maker_payment_spend_fee = other_coin .get_receiver_trade_fee(stage) .compat() .await @@ -2393,8 +2393,8 @@ pub async fn check_balance_for_taker_swap( TakerSwapPreparedParams { dex_fee: dex_fee.total_spend_amount(), fee_to_send_dex_fee, - funding_fee: taker_payment_trade_fee, - maker_payment_spend_trade_fee, + funding_fee, + maker_payment_spend_fee, } }, }; @@ -2413,8 +2413,8 @@ pub async fn check_balance_for_taker_swap( Some(taker_fee), ) .await?; - if !params.maker_payment_spend_trade_fee.paid_from_trading_vol { - check_other_coin_balance_for_swap(ctx, other_coin, swap_uuid, params.maker_payment_spend_trade_fee).await?; + if !params.maker_payment_spend_fee.paid_from_trading_vol { + check_other_coin_balance_for_swap(ctx, other_coin, swap_uuid, params.maker_payment_spend_fee).await?; } Ok(()) } @@ -2490,7 +2490,7 @@ pub async fn taker_swap_trade_preimage( dex_fee: dex_amount.total_spend_amount(), fee_to_send_dex_fee: fee_to_send_taker_fee.clone(), funding_fee: my_coin_trade_fee.clone(), - maker_payment_spend_trade_fee: other_coin_trade_fee.clone(), + maker_payment_spend_fee: other_coin_trade_fee.clone(), }; check_balance_for_taker_swap( ctx, diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 95b58eefdd..ec468d4d51 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -9,7 +9,7 @@ use crate::mm2::lp_swap::{broadcast_swap_v2_msg_every, check_balance_for_taker_s use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use coins::utxo::sat_from_big_decimal; -use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, GenTakerFundingSpendArgs, +use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, GenTakerPaymentPreimageArgs, GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundPaymentArgs, SendTakerFundingArgs, SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, TradeFee, TradePreimageValue, Transaction, TxPreimageWithSig, @@ -978,18 +978,18 @@ impl, state_machine: &mut Self::StateMachine) -> StateResult { let unique_data = state_machine.unique_data(); - let args = GenTakerFundingSpendArgs { + let args = GenTakerPaymentPreimageArgs { funding_tx: &self.taker_funding, maker_pub: &self.negotiation_data.taker_coin_htlc_pub_from_maker, taker_pub: &state_machine.taker_coin.derive_htlc_pubkey_v2(&unique_data), @@ -2017,7 +2017,7 @@ impl Date: Fri, 10 May 2024 20:00:16 +0200 Subject: [PATCH 20/38] wrong name in the protobuf file --- mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs | 4 ++-- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 4 ++-- mm2src/mm2_main/src/lp_swap/swap_v2.proto | 4 ++-- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs b/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs index b3a1de28e2..ad9a47e5c6 100644 --- a/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs +++ b/mm2src/mm2_main/src/lp_swap/komodefi.swap_v2.pb.rs @@ -106,9 +106,9 @@ pub struct MakerPaymentInfo { #[prost(bytes = "vec", optional, tag = "2")] pub next_step_instructions: ::core::option::Option<::prost::alloc::vec::Vec>, #[prost(bytes = "vec", tag = "3")] - pub funding_preimage_sig: ::prost::alloc::vec::Vec, + pub taker_payment_preimage_sig: ::prost::alloc::vec::Vec, #[prost(bytes = "vec", tag = "4")] - pub funding_preimage_tx: ::prost::alloc::vec::Vec, + pub taker_payment_preimage_tx: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 43ddc0a74f..0b38d613cb 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -1294,8 +1294,8 @@ impl p, Err(e) => { @@ -1394,7 +1394,7 @@ impl p, Err(e) => { @@ -1791,7 +1791,7 @@ impl Date: Fri, 10 May 2024 20:01:29 +0200 Subject: [PATCH 21/38] format --- mm2src/coins/utxo/utxo_common.rs | 6 +++--- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 20 ++++---------------- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 10 +--------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 330164fa3a..a29e190aed 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -13,9 +13,9 @@ use crate::utxo::utxo_hd_wallet::UtxoHDAddress; use crate::utxo::utxo_withdraw::{InitUtxoWithdraw, StandardUtxoWithdraw, UtxoWithdraw}; use crate::watcher_common::validate_watcher_reward; use crate::{scan_for_new_addresses_impl, CanRefundHtlc, CoinBalance, CoinWithDerivationMethod, ConfirmPaymentInput, - DexFee, GenPreimageResult, GenTakerPaymentPreimageArgs, GenTakerPaymentSpendArgs, GetWithdrawSenderAddress, - RawTransactionError, RawTransactionRequest, RawTransactionRes, RawTransactionResult, - RefundFundingSecretArgs, RefundMakerPaymentArgs, RefundPaymentArgs, RewardTarget, + DexFee, GenPreimageResult, GenTakerPaymentPreimageArgs, GenTakerPaymentSpendArgs, + GetWithdrawSenderAddress, RawTransactionError, RawTransactionRequest, RawTransactionRes, + RawTransactionResult, RefundFundingSecretArgs, RefundMakerPaymentArgs, RefundPaymentArgs, RewardTarget, SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SendTakerFundingArgs, SignRawTransactionEnum, SignRawTransactionRequest, SignUtxoTransactionParams, SignatureError, SignatureResult, SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 0b38d613cb..feed12061d 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -679,10 +679,7 @@ impl { + MakerSwapEvent::Initialized { maker_payment_fee, .. } => { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); let maker_coin_ticker: String = self.maker_coin.ticker().into(); let new_locked = LockedAmountInfo { @@ -724,18 +721,9 @@ impl::DbRepr as StateMachineDbRepr>::Event, ) { match event { - MakerSwapEvent::Initialized { - maker_payment_fee, - .. - } - | MakerSwapEvent::WaitingForTakerFunding { - maker_payment_fee, - .. - } - | MakerSwapEvent::TakerFundingReceived { - maker_payment_fee, - .. - } => { + MakerSwapEvent::Initialized { maker_payment_fee, .. } + | MakerSwapEvent::WaitingForTakerFunding { maker_payment_fee, .. } + | MakerSwapEvent::TakerFundingReceived { maker_payment_fee, .. } => { let swaps_ctx = SwapsContext::from_ctx(&self.ctx).expect("from_ctx should not fail at this point"); let maker_coin_ticker: String = self.maker_coin.ticker().into(); let new_locked = LockedAmountInfo { diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index b2d258441b..d7853cfd84 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -2404,15 +2404,7 @@ pub async fn check_balance_for_taker_swap( fee_to_send_dex_fee: params.fee_to_send_dex_fee, }; - check_my_coin_balance_for_swap( - ctx, - my_coin, - swap_uuid, - volume, - params.funding_fee, - Some(taker_fee), - ) - .await?; + check_my_coin_balance_for_swap(ctx, my_coin, swap_uuid, volume, params.funding_fee, Some(taker_fee)).await?; if !params.maker_payment_spend_fee.paid_from_trading_vol { check_other_coin_balance_for_swap(ctx, other_coin, swap_uuid, params.maker_payment_spend_fee).await?; } From d18bf96676d214962d0e506de754a444168532fe Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 10 May 2024 20:34:46 +0200 Subject: [PATCH 22/38] fix the names in tests --- mm2src/coins/lp_coins.rs | 8 +- mm2src/coins/utxo/utxo_common.rs | 2 +- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 2 +- .../tests/docker_tests/swap_proto_v2_tests.rs | 90 +++++++++---------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index d69b506647..cbf0528d60 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1236,8 +1236,8 @@ pub struct SendTakerFundingArgs<'a> { pub maker_pub: &'a [u8], /// DEX fee pub dex_fee: &'a DexFee, - /// The extra fee added to the trading volume to cover the taker payment spend transaction fees - pub taker_payment_spend_fee: BigDecimal, + /// The extra fee added to the trading volume to cover the taker payment transaction fees + pub taker_payment_fee: BigDecimal, /// Additional reward for maker (premium) pub premium_amount: BigDecimal, /// Actual volume of taker's payment @@ -1274,7 +1274,7 @@ pub struct GenTakerPaymentPreimageArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub taker_payment_time_lock: u64, /// The hash of the secret generated by maker pub maker_secret_hash: &'a [u8], - /// The extra fee added to the trading volume to cover the taker payment spend transaction fees + /// The extra fee added to the trading volume to cover the taker payment transaction fees pub taker_payment_fee: BigDecimal, } @@ -1290,7 +1290,7 @@ pub struct ValidateTakerFundingArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub other_pub: &'a Coin::Pubkey, /// DEX fee amount pub dex_fee: &'a DexFee, - /// The extra fee added to the trading volume to cover the taker payment spend transaction fees + /// The extra fee added to the trading volume to cover the taker payment transaction fees pub taker_payment_fee: BigDecimal, /// Additional reward for maker (premium) pub premium_amount: BigDecimal, diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index a29e190aed..dada2e10a4 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -4890,7 +4890,7 @@ where let total_amount = &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount - + &args.taker_payment_spend_fee; + + &args.taker_payment_fee; let SwapPaymentOutputsResult { payment_address, diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 87db05444d..67fcd4dde2 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -1263,7 +1263,7 @@ impl Date: Mon, 20 May 2024 12:48:02 +0200 Subject: [PATCH 23/38] suggestions from aline: use is_zero, parse string instead of float to avoid weird precision --- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index feed12061d..30a7e80633 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -25,6 +25,7 @@ use mm2_libp2p::Secp256k1PubkeySerialize; use mm2_number::{BigDecimal, MmNumber}; use mm2_state_machine::prelude::*; use mm2_state_machine::storable_state_machine::*; +use num_traits::Zero; use primitives::hash::H256; use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; use secp256k1::PublicKey; @@ -811,7 +812,6 @@ impl fee, Err(e) => { @@ -962,13 +962,13 @@ impl Date: Tue, 18 Jun 2024 11:22:19 +0200 Subject: [PATCH 24/38] fix tests not compiling after merge --- mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs index 8d4cd39b6c..277a8de7bd 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs @@ -298,7 +298,7 @@ fn maker_rejects_funding_low_fee() { swap_unique_data: &[], }; let taker_funding_utxo_tx = block_on(taker_coin.send_taker_funding(send_args)).unwrap(); - log!("Funding tx {:02x}", taker_funding_utxo_tx.tx_hash()); + log!("Funding tx {:02x}", taker_funding_utxo_tx.tx_hash_as_bytes()); let validate_args = ValidateTakerFundingArgs { funding_tx: &taker_funding_utxo_tx, @@ -347,7 +347,7 @@ fn taker_rejects_taker_payment_preimage_low_fee() { swap_unique_data: &[], }; let taker_funding_utxo_tx = block_on(taker_coin.send_taker_funding(send_args)).unwrap(); - log!("Funding tx {:02x}", taker_funding_utxo_tx.tx_hash()); + log!("Funding tx {:02x}", taker_funding_utxo_tx.tx_hash_as_bytes()); let validate_args = ValidateTakerFundingArgs { funding_tx: &taker_funding_utxo_tx, From 130fc8815b532f1870e08b9936502744e42c3de6 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Tue, 2 Jul 2024 20:07:23 +0200 Subject: [PATCH 25/38] claimation -> claiming --- mm2src/coins/lp_coins.rs | 4 ++-- mm2src/coins/utxo/utxo_common.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 141718b599..f89d6e236c 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1683,7 +1683,7 @@ pub trait MakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Get the fee to be paid for the processing of the maker payment transaction. async fn get_maker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; - /// Get the fee to be paid for the processing of the maker payment spend transaction aka the claimation transaction. + /// Get the fee to be paid for the processing of the maker payment spend transaction aka the claiming transaction. async fn get_maker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; } @@ -1889,7 +1889,7 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Get the fee to be paid for the processing of the funding transaction. /// Txs in success case (no refund) go as follows: /// Chain A: funding -> taker payment -> taker payment spend (aka preimage) (to the maker & dex) - /// Chain B: maker payment -> maker payment spend (aka claimation) (to the taker) + /// Chain B: maker payment -> maker payment spend (aka claiming) (to the taker) async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; /// Get the fee to be paid for the processing of the funding-spend transaction aka taker payment transaction. diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index c5b48cc85e..21e9d59bab 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -4854,7 +4854,7 @@ where let taker_htlc_key_pair = coin.derive_htlc_key_pair(args.swap_unique_data); // FIXME: // 1- Let the preimage tx fee be handled by the taker as well. - // 2- Who pays the maker payment fee? Take in considration that a nicer UX would be to hand the taker the full amount they requested. (so account for maker payment fee and taker claimation fee) + // 2- Who pays the maker payment fee? Take in considration that a nicer UX would be to hand the taker the full amount they requested. (so account for maker payment fee and taker claiming fee) let total_amount = &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount From ec3ffe353d644a4050af7c6469ae5f810ad34a8d Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Tue, 2 Jul 2024 20:08:46 +0200 Subject: [PATCH 26/38] remove unused method --- mm2src/coins/lp_coins.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index f89d6e236c..b9a2fa935e 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1892,13 +1892,6 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Chain B: maker payment -> maker payment spend (aka claiming) (to the taker) async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; - /// Get the fee to be paid for the processing of the funding-spend transaction aka taker payment transaction. - /// - /// Don't use this method, use [TakerCoinSwapOpsV2::get_taker_payment_fee] instead. - async fn get_funding_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { - self.get_taker_payment_fee(stage).await - } - /// Get the fee to be paid for the processing of the taker payment transaction. async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; From 9cb98185dcaf6c6aa8ffb951b891ffd7b195ea4c Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 3 Jul 2024 10:04:02 +0200 Subject: [PATCH 27/38] move the fixme to the appropriate place also changed to todo --- mm2src/coins/utxo/utxo_common.rs | 2 -- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 21e9d59bab..d9a837bf96 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -1072,8 +1072,6 @@ async fn gen_taker_funding_spend_preimage( // If calculated fee is less than instructed fee, use instructed fee because it was never intended // to be deposited to us (maker). If the calculated fee is larger, we will incur the fee difference // just to make sure the transaction is confirmed quickly. - // FIXME: Possible abuse vector is that the taker can always send the fee to be just above 90% of the - // expected fee knowing that the maker will always accept incurring the difference. calculated_fee.max(taker_instructed_fee) }, FundingSpendFeeSetting::UseExact(f) => f, diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 146c29f96d..cbeacb9ce3 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -968,7 +968,9 @@ impl Date: Wed, 3 Jul 2024 10:13:44 +0200 Subject: [PATCH 28/38] set preimage & maker payment fee as a todo --- mm2src/coins/utxo/utxo_common.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index d9a837bf96..98eb845b9f 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -4850,9 +4850,10 @@ where T: UtxoCommonOps + GetUtxoListOps + SwapOps, { let taker_htlc_key_pair = coin.derive_htlc_key_pair(args.swap_unique_data); - // FIXME: + // TODO: // 1- Let the preimage tx fee be handled by the taker as well. // 2- Who pays the maker payment fee? Take in considration that a nicer UX would be to hand the taker the full amount they requested. (so account for maker payment fee and taker claiming fee) + // 3- For the nicer UX, we also want to account for the maker payment spend fee beforehand. let total_amount = &args.dex_fee.total_spend_amount().to_decimal() + &args.premium_amount + &args.trading_amount From a2e4bfa9433b8a8b47004540fba7485346a064f8 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 3 Jul 2024 10:17:45 +0200 Subject: [PATCH 29/38] remove fixme about the locktime used for btc revising the commit history, looks like this was deliberate --- mm2src/mm2_main/src/lp_swap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index a32e0f1bce..184f8e3c05 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -766,7 +766,6 @@ pub fn lp_atomic_locktime_v2( if taker_coin.contains("-lightning") { // A good value for lightning taker locktime is about 24 hours to find a good 3 hop or less path for the payment get_payment_locktime() * 12 - // FIXME: Shouldn't BTC get x10 time, like in V1? } else if maker_coin == "BTC" || taker_coin == "BTC" || coin_with_4x_locktime(maker_coin) From c383862de70c3504f6358e18b9005b688910ecf2 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 3 Jul 2024 10:35:05 +0200 Subject: [PATCH 30/38] sighashtype is encoded as four bytes even tho it's just one ref. https://bitcoin.stackexchange.com/questions/48108/why-are-sighash-flags-signed-as-4-bytes-when-only-1-byte-is-included-in-the-tran --- mm2src/mm2_bitcoin/script/src/sign.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/mm2src/mm2_bitcoin/script/src/sign.rs b/mm2src/mm2_bitcoin/script/src/sign.rs index d750c97575..1f8e746e82 100644 --- a/mm2src/mm2_bitcoin/script/src/sign.rs +++ b/mm2src/mm2_bitcoin/script/src/sign.rs @@ -371,7 +371,6 @@ impl TransactionInputSigner { let mut stream = Stream::default(); stream.append(&tx); - // FIXME: Serialize as u8 or u32? stream.append(&(sighashtype as u32)); let out = stream.out(); match self.hash_algo { @@ -552,7 +551,6 @@ impl TransactionInputSigner { sig_hash_stream.append(&self.lock_time); sig_hash_stream.append(&self.expiry_height); sig_hash_stream.append(&self.value_balance); - // FIXME: Serialize as u8 or u32? sig_hash_stream.append(&(sighashtype as u32)); sig_hash_stream.append(&self.inputs[input_index].previous_output); From a08a9818a2ddaf392c63ebdf7daa3752c25d6a29 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 3 Jul 2024 15:26:17 +0200 Subject: [PATCH 31/38] move the forkid fixme into a todo for later --- mm2src/mm2_bitcoin/script/src/sign.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_bitcoin/script/src/sign.rs b/mm2src/mm2_bitcoin/script/src/sign.rs index 1f8e746e82..a757dab5d9 100644 --- a/mm2src/mm2_bitcoin/script/src/sign.rs +++ b/mm2src/mm2_bitcoin/script/src/sign.rs @@ -401,7 +401,7 @@ impl TransactionInputSigner { stream.append(&self.inputs[input_index].sequence); stream.append(&hash_outputs); stream.append(&self.lock_time); - // FIXME: Serialize as u8 or u32? Also, 24-bit fork id? + // TODO: This is missing the fork id. stream.append(&(sighashtype as u32)); // this also includes 24-bit fork id. which is 0 for BitcoinCash let out = stream.out(); dhash256(&out) From ba0037f8b061311073135f933c90b193c4da1b18 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 4 Jul 2024 15:47:28 +0200 Subject: [PATCH 32/38] cap fee to the one instruced by taker, allow using less --- mm2src/coins/utxo/utxo_common.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 98eb845b9f..7e0e6c62ef 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -1069,10 +1069,9 @@ async fn gen_taker_funding_spend_preimage( .await?; let taker_instructed_fee = sat_from_big_decimal(&args.taker_payment_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; - // If calculated fee is less than instructed fee, use instructed fee because it was never intended - // to be deposited to us (maker). If the calculated fee is larger, we will incur the fee difference - // just to make sure the transaction is confirmed quickly. - calculated_fee.max(taker_instructed_fee) + // Cap the paid fee to the taker instructed fee. + // Since any fee above that will be paid from our (maker) trading volume. + calculated_fee.min(taker_instructed_fee) }, FundingSpendFeeSetting::UseExact(f) => f, }; @@ -1166,9 +1165,11 @@ pub async fn validate_taker_payment_preimage( let instructed_fee = sat_from_big_decimal(&gen_args.taker_payment_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; - if actual_fee < instructed_fee { + if actual_fee > instructed_fee { + // Reject a high fee. Such fee will typically be paid from the maker's trading volume, + // but the maker might fail the swap later and this would make us incur this fee instead. return MmError::err(ValidateTakerFundingSpendPreimageError::UnexpectedPreimageFee(format!( - "A fee of {} was used, less than the agreed upon fee of {}", + "A fee of {} was used, more than the agreed upon fee of {}.", actual_fee, instructed_fee ))); } From c970e250d82bdb434dfec7fc0b4235ece85d6bf7 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 4 Jul 2024 18:15:47 +0200 Subject: [PATCH 33/38] implement other fee calculation methods --- mm2src/coins/utxo/utxo_common.rs | 245 +++++++++++++++---- mm2src/coins/utxo/utxo_standard.rs | 50 +++- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 6 +- 3 files changed, 243 insertions(+), 58 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 7e0e6c62ef..a9ab5fdd6f 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -881,59 +881,204 @@ enum FundingSpendFeeSetting { UseExact(u64), } -/// Returns the taker payment transaction size in vbytes. -pub async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { - let preimage = TransactionInputSigner { - lock_time: 0, - version: coin.as_ref().conf.tx_version, - n_time: None, - overwintered: coin.as_ref().conf.overwintered, - inputs: vec![UnsignedTransactionInput { - sequence: SEQUENCE_FINAL, - previous_output: OutPoint { - hash: H256::default(), - index: DEFAULT_SWAP_VOUT as u32, - }, - prev_script: Vec::new().into(), - amount: 0, - }], - outputs: vec![TransactionOutput { - value: 0, - script_pubkey: Builder::build_p2sh(&AddressHashEnum::default_address_hash()).to_bytes(), - }], - expiry_height: 0, - join_splits: vec![], - shielded_spends: vec![], - shielded_outputs: vec![], - value_balance: 0, - version_group_id: coin.as_ref().conf.version_group_id, - consensus_branch_id: coin.as_ref().conf.consensus_branch_id, - zcash: coin.as_ref().conf.zcash, - posv: coin.as_ref().conf.is_posv, - str_d_zeel: None, - hash_algo: coin.as_ref().tx_hash_algo.into(), - }; +pub mod tx_sizes { + use super::*; + + /// Returns the taker funding transaction size in vbytes. + pub async fn get_funding_tx_size(_coin: &impl UtxoCommonOps) -> usize { + // This depends on what coins being spent so might be a bit clumsy. + // Since this is the first tx anyway, we won't need a utxo locking mechanism + // to prevent certain utxos from being spent in other swaps happening in parallel. + // We just need to make sure that we deliver the correct trading volume and not less. + + // Inspect `get_sender_trade_fee`, but I don't think it nails it correctly. + todo!() + } - let redeem_script = swap_proto_v2_scripts::taker_funding_script( - 0, - H160::default().as_slice(), - &Public::default(), - &Public::default(), - ); + /// Returns the maker payment transaction size in vbytes. + pub async fn get_maker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { + // Maker payment is similar to funding tx in that it spends coins directly from the user's + // wallet and sends them to P2SH address. + get_funding_tx_size(coin).await + } - let mut final_tx: UtxoTx = preimage.into(); - final_tx.inputs[0].script_sig = Builder::default() - // Maximum of 72 byte maker signature + a sighash byte. - .push_data(&[0; 72 + 1]) - // Maximum of 72 byte taker signature + a sighash byte. - .push_data(&[0; 72 + 1]) - .push_opcode(Opcode::OP_1) - .push_opcode(Opcode::OP_0) - .push_data(&redeem_script) - .into_bytes(); + /// Returns the taker payment transaction size in vbytes. + pub async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { + let preimage = TransactionInputSigner { + lock_time: 0, + version: coin.as_ref().conf.tx_version, + n_time: None, + overwintered: coin.as_ref().conf.overwintered, + inputs: vec![UnsignedTransactionInput { + sequence: SEQUENCE_FINAL, + previous_output: OutPoint { + hash: H256::default(), + index: DEFAULT_SWAP_VOUT as u32, + }, + prev_script: Vec::new().into(), + amount: 0, + }], + outputs: vec![ + // This output is used in taker payment spent tx. + TransactionOutput { + value: 0, + script_pubkey: Builder::build_p2sh(&AddressHashEnum::default_address_hash()).to_bytes(), + }, + ], + expiry_height: 0, + join_splits: vec![], + shielded_spends: vec![], + shielded_outputs: vec![], + value_balance: 0, + version_group_id: coin.as_ref().conf.version_group_id, + consensus_branch_id: coin.as_ref().conf.consensus_branch_id, + zcash: coin.as_ref().conf.zcash, + posv: coin.as_ref().conf.is_posv, + str_d_zeel: None, + hash_algo: coin.as_ref().tx_hash_algo.into(), + }; + + let redeem_script = swap_proto_v2_scripts::taker_funding_script( + 0, + H160::default().as_slice(), + &Public::default(), + &Public::default(), + ); + + let mut final_tx: UtxoTx = preimage.into(); + final_tx.inputs[0].script_sig = Builder::default() + // Maximum of 72 byte maker signature + a sighash byte. + .push_data(&[0; 72 + 1]) + // Maximum of 72 byte taker signature + a sighash byte. + .push_data(&[0; 72 + 1]) + .push_opcode(Opcode::OP_1) + .push_opcode(Opcode::OP_0) + .push_data(&redeem_script) + .into_bytes(); + + // We aren't spending from the segwit address, we are spending from a P2SH address. + tx_size_in_v_bytes(&UtxoAddressFormat::Standard, &final_tx) + } + + /// Returns the taker payment spend transaction size in vbytes. + pub async fn get_taker_payment_spend_tx_size(coin: &impl UtxoCommonOps) -> usize { + let preimage = TransactionInputSigner { + lock_time: 0, + version: coin.as_ref().conf.tx_version, + n_time: None, + overwintered: coin.as_ref().conf.overwintered, + inputs: vec![UnsignedTransactionInput { + sequence: SEQUENCE_FINAL, + previous_output: OutPoint { + hash: H256::default(), + index: DEFAULT_SWAP_VOUT as u32, + }, + prev_script: Vec::new().into(), + amount: 0, + }], + outputs: vec![ + // An output for the dex. + TransactionOutput { + value: 0, + script_pubkey: Builder::build_p2sh(&AddressHashEnum::default_address_hash()).to_bytes(), + }; + // And another for the maker. + 2 + ], + expiry_height: 0, + join_splits: vec![], + shielded_spends: vec![], + shielded_outputs: vec![], + value_balance: 0, + version_group_id: coin.as_ref().conf.version_group_id, + consensus_branch_id: coin.as_ref().conf.consensus_branch_id, + zcash: coin.as_ref().conf.zcash, + posv: coin.as_ref().conf.is_posv, + str_d_zeel: None, + hash_algo: coin.as_ref().tx_hash_algo.into(), + }; + + let redeem_script = swap_proto_v2_scripts::taker_payment_script( + 0, + H160::default().as_slice(), + &Public::default(), + &Public::default(), + ); + + let mut final_tx: UtxoTx = preimage.into(); + final_tx.inputs[0].script_sig = Builder::default() + // Maximum of 72 byte maker signature + a sighash byte. + .push_data(&[0; 72 + 1]) + // Maximum of 72 byte taker signature + a sighash byte. + .push_data(&[0; 72 + 1]) + // Maker's secret hash. + .push_data(&[0; 32]) + .push_opcode(Opcode::OP_0) + .push_data(&redeem_script) + .into_bytes(); + + // We aren't spending from the segwit address, we are spending from a P2SH address. + tx_size_in_v_bytes(&UtxoAddressFormat::Standard, &final_tx) + } + + /// Returns the maker payment spend transaction size in vbytes. + pub async fn get_maker_payment_spend_tx_size(coin: &impl UtxoCommonOps) -> usize { + let preimage = TransactionInputSigner { + lock_time: 0, + version: coin.as_ref().conf.tx_version, + n_time: None, + overwintered: coin.as_ref().conf.overwintered, + inputs: vec![UnsignedTransactionInput { + sequence: SEQUENCE_FINAL, + previous_output: OutPoint { + hash: H256::default(), + index: DEFAULT_SWAP_VOUT as u32, + }, + prev_script: Vec::new().into(), + amount: 0, + }], + outputs: vec![ + // An output for the taker + TransactionOutput { + value: 0, + script_pubkey: Builder::build_p2sh(&AddressHashEnum::default_address_hash()).to_bytes(), + }, + ], + expiry_height: 0, + join_splits: vec![], + shielded_spends: vec![], + shielded_outputs: vec![], + value_balance: 0, + version_group_id: coin.as_ref().conf.version_group_id, + consensus_branch_id: coin.as_ref().conf.consensus_branch_id, + zcash: coin.as_ref().conf.zcash, + posv: coin.as_ref().conf.is_posv, + str_d_zeel: None, + hash_algo: coin.as_ref().tx_hash_algo.into(), + }; - // We aren't spending from the segwit address, we are spending from a P2SH address. - tx_size_in_v_bytes(&UtxoAddressFormat::Standard, &final_tx) + let redeem_script = swap_proto_v2_scripts::maker_payment_script( + 0, + H160::default().as_slice(), + H160::default().as_slice(), + &Public::default(), + &Public::default(), + ); + + let mut final_tx: UtxoTx = preimage.into(); + final_tx.inputs[0].script_sig = Builder::default() + // Maximum of 72 byte taker signature + a sighash byte. + .push_data(&[0; 72 + 1]) + // Maker's secret hash. + .push_data(&[0; 32]) + .push_opcode(Opcode::OP_1) + .push_opcode(Opcode::OP_0) + .push_data(&redeem_script) + .into_bytes(); + + // We aren't spending from the segwit address, we are spending from a P2SH address. + tx_size_in_v_bytes(&UtxoAddressFormat::Standard, &final_tx) + } } async fn p2sh_spending_tx_preimage( diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index b9f09b662f..6086728af4 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -651,9 +651,29 @@ impl MakerCoinSwapOpsV2 for UtxoStandardCoin { utxo_common::spend_maker_payment_v2(self, args).await } - async fn get_maker_payment_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + async fn get_maker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { + let maker_payment_tx_size = utxo_common::tx_sizes::get_maker_payment_tx_size(self).await; + let fee_sat = self.get_htlc_spend_fee(maker_payment_tx_size as u64, stage).await?; + let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); + Ok(TradeFee { + coin: self.as_ref().conf.ticker.clone(), + amount, + paid_from_trading_vol: true, + }) + } - async fn get_maker_payment_spend_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + async fn get_maker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { + let maker_payment_spend_tx_size = utxo_common::tx_sizes::get_maker_payment_spend_tx_size(self).await; + let fee_sat = self + .get_htlc_spend_fee(maker_payment_spend_tx_size as u64, stage) + .await?; + let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); + Ok(TradeFee { + coin: self.as_ref().conf.ticker.clone(), + amount, + paid_from_trading_vol: true, + }) + } } #[async_trait] @@ -832,10 +852,19 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { *self.derive_htlc_key_pair(swap_unique_data).public() } - async fn get_funding_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { + let funding_tx_size = utxo_common::tx_sizes::get_funding_tx_size(self).await; + let fee_sat = self.get_htlc_spend_fee(funding_tx_size as u64, stage).await?; + let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); + Ok(TradeFee { + coin: self.as_ref().conf.ticker.clone(), + amount, + paid_from_trading_vol: true, + }) + } async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { - let taker_payment_tx_size = utxo_common::get_taker_payment_tx_size(self).await; + let taker_payment_tx_size = utxo_common::tx_sizes::get_taker_payment_tx_size(self).await; let fee_sat = self.get_htlc_spend_fee(taker_payment_tx_size as u64, stage).await?; let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); Ok(TradeFee { @@ -845,7 +874,18 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { }) } - async fn get_taker_payment_spend_fee(&self, _stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + async fn get_taker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { + let taker_payment_spend_tx_size = utxo_common::tx_sizes::get_taker_payment_spend_tx_size(self).await; + let fee_sat = self + .get_htlc_spend_fee(taker_payment_spend_tx_size as u64, stage) + .await?; + let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); + Ok(TradeFee { + coin: self.as_ref().conf.ticker.clone(), + amount, + paid_from_trading_vol: true, + }) + } } #[async_trait] diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index b972b99ef1..0507bfdd0c 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -969,7 +969,7 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetMakerPaymentSpendFee(e.to_string()); @@ -980,7 +980,7 @@ impl Date: Thu, 4 Jul 2024 19:49:33 +0200 Subject: [PATCH 34/38] use get_taker_payment_fee instead of const size get_htlc_spend_fee --- mm2src/coins/utxo/utxo_common.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index a9ab5fdd6f..d0764e1dc6 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -19,8 +19,8 @@ use crate::{scan_for_new_addresses_impl, CanRefundHtlc, CoinBalance, CoinWithDer SearchForSwapTxSpendInput, SendMakerPaymentArgs, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SendTakerFundingArgs, SignRawTransactionEnum, SignRawTransactionRequest, SignUtxoTransactionParams, SignatureError, SignatureResult, SpendMakerPaymentArgs, SpendPaymentArgs, SwapOps, - SwapTxTypeWithSecretHash, TradePreimageValue, TransactionData, TransactionFut, TransactionResult, - TxFeeDetails, TxGenError, TxMarshalingErr, TxPreimageWithSig, ValidateAddressResult, + SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, TradePreimageValue, TransactionData, TransactionFut, + TransactionResult, TxFeeDetails, TxGenError, TxMarshalingErr, TxPreimageWithSig, ValidateAddressResult, ValidateOtherPubKeyErr, ValidatePaymentFut, ValidatePaymentInput, ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, ValidateTakerFundingSpendPreimageError, ValidateTakerFundingSpendPreimageResult, ValidateTakerPaymentSpendPreimageError, @@ -1184,7 +1184,7 @@ pub async fn p2sh_spending_tx(coin: &T, input: P2SHSpendingTxI type GenPreimageResInner = MmResult; async fn gen_taker_funding_spend_preimage( - coin: &T, + coin: &(impl UtxoCommonOps + TakerCoinSwapOpsV2), args: &GenTakerPaymentPreimageArgs<'_, T>, n_time: NTimeSetting, fee: FundingSpendFeeSetting, @@ -1210,8 +1210,12 @@ async fn gen_taker_funding_spend_preimage( let fee = match fee { FundingSpendFeeSetting::GetFromCoin => { let calculated_fee = coin - .get_htlc_spend_fee(DEFAULT_SWAP_TX_SPEND_SIZE, &FeeApproxStage::WithoutApprox) - .await?; + .get_taker_payment_fee(&FeeApproxStage::WithoutApprox) + .await + .unwrap() + .amount + .to_decimal(); + let calculated_fee = sat_from_big_decimal(&calculated_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; let taker_instructed_fee = sat_from_big_decimal(&args.taker_payment_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; // Cap the paid fee to the taker instructed fee. @@ -1247,7 +1251,7 @@ async fn gen_taker_funding_spend_preimage( } pub async fn gen_and_sign_taker_payment_preimage( - coin: &T, + coin: &(impl UtxoCommonOps + TakerCoinSwapOpsV2), args: &GenTakerPaymentPreimageArgs<'_, T>, htlc_keypair: &KeyPair, ) -> GenPreimageResult { @@ -1282,8 +1286,8 @@ pub async fn gen_and_sign_taker_payment_preimage( /// Common implementation of taker funding spend preimage validation for UTXO coins. /// Checks maker's signature and compares received preimage with the expected tx. -pub async fn validate_taker_payment_preimage( - coin: &T, +pub async fn validate_taker_payment_preimage( + coin: &(impl UtxoCommonOps + TakerCoinSwapOpsV2), gen_args: &GenTakerPaymentPreimageArgs<'_, T>, preimage: &TxPreimageWithSig, ) -> ValidateTakerFundingSpendPreimageResult { From db11ed9335d5433d711aa930b4ac23e632d09dcd Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 5 Jul 2024 12:03:58 +0200 Subject: [PATCH 35/38] use a more idiomatic syntax for func generic bounds --- mm2src/coins/utxo/utxo_common.rs | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index d0764e1dc6..54193ba7f2 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -1183,12 +1183,16 @@ pub async fn p2sh_spending_tx(coin: &T, input: P2SHSpendingTxI type GenPreimageResInner = MmResult; -async fn gen_taker_funding_spend_preimage( - coin: &(impl UtxoCommonOps + TakerCoinSwapOpsV2), +async fn gen_taker_funding_spend_preimage( + coin: &Coin, args: &GenTakerPaymentPreimageArgs<'_, T>, n_time: NTimeSetting, fee: FundingSpendFeeSetting, -) -> GenPreimageResInner { +) -> GenPreimageResInner +where + T: UtxoCommonOps, + Coin: UtxoCommonOps + TakerCoinSwapOpsV2, +{ let payment_time_lock = args .taker_payment_time_lock .try_into() @@ -1250,11 +1254,15 @@ async fn gen_taker_funding_spend_preimage( .map_to_mm(TxGenError::Legacy) } -pub async fn gen_and_sign_taker_payment_preimage( - coin: &(impl UtxoCommonOps + TakerCoinSwapOpsV2), +pub async fn gen_and_sign_taker_payment_preimage( + coin: &Coin, args: &GenTakerPaymentPreimageArgs<'_, T>, htlc_keypair: &KeyPair, -) -> GenPreimageResult { +) -> GenPreimageResult +where + T: UtxoCommonOps, + Coin: UtxoCommonOps + TakerCoinSwapOpsV2, +{ let funding_time_lock = args .funding_time_lock .try_into() @@ -1286,11 +1294,15 @@ pub async fn gen_and_sign_taker_payment_preimage( /// Common implementation of taker funding spend preimage validation for UTXO coins. /// Checks maker's signature and compares received preimage with the expected tx. -pub async fn validate_taker_payment_preimage( - coin: &(impl UtxoCommonOps + TakerCoinSwapOpsV2), +pub async fn validate_taker_payment_preimage( + coin: &Coin, gen_args: &GenTakerPaymentPreimageArgs<'_, T>, preimage: &TxPreimageWithSig, -) -> ValidateTakerFundingSpendPreimageResult { +) -> ValidateTakerFundingSpendPreimageResult +where + T: UtxoCommonOps, + Coin: UtxoCommonOps + TakerCoinSwapOpsV2, +{ let funding_amount = gen_args .funding_tx .first_output() From 28fc4420d41a75b77447ccf0458c4179b120fe25 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 5 Jul 2024 14:01:56 +0200 Subject: [PATCH 36/38] broadcast every 30s instead of 600s --- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 0507bfdd0c..6d491e74fd 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -1339,9 +1339,7 @@ impl Date: Mon, 29 Jul 2024 11:36:41 +0200 Subject: [PATCH 37/38] add a missing fixme always rename discuss markers to fixmes since i forget about them xD --- mm2src/coins/utxo/utxo_common.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index 54193ba7f2..c095cf446d 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -891,7 +891,7 @@ pub mod tx_sizes { // to prevent certain utxos from being spent in other swaps happening in parallel. // We just need to make sure that we deliver the correct trading volume and not less. - // Inspect `get_sender_trade_fee`, but I don't think it nails it correctly. + // FIXME: Inspect `get_sender_trade_fee`, but I don't think it nails it correctly. todo!() } @@ -4030,7 +4030,7 @@ pub fn get_trade_fee(coin: T) -> Box Date: Mon, 29 Jul 2024 13:39:44 +0200 Subject: [PATCH 38/38] use `get_sender_trade_fee` for non-htlc TXs there is no calculatable tx_size for other tx (non-htlc) (like funding and maker payment txs). their fees depend really on the utxos we have and whether they are segwit or not. used get_sender_trade_fee for now, though I think this method needs reviewing since its doc comment doesn't make a lot of sense --- mm2src/coins/lp_coins.rs | 10 ++--- mm2src/coins/test_coin.rs | 6 +-- mm2src/coins/utxo/utxo_common.rs | 31 ++----------- mm2src/coins/utxo/utxo_standard.rs | 46 ++++++++------------ mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 17 +++----- mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 18 +++----- 6 files changed, 43 insertions(+), 85 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index b9a2fa935e..816e9ca98a 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1681,10 +1681,10 @@ pub trait MakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result; /// Get the fee to be paid for the processing of the maker payment transaction. - async fn get_maker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + async fn get_maker_payment_fee(&self, value: TradePreimageValue) -> TradePreimageResult; /// Get the fee to be paid for the processing of the maker payment spend transaction aka the claiming transaction. - async fn get_maker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + async fn get_maker_payment_spend_fee(&self) -> TradePreimageResult; } #[async_trait] @@ -1890,13 +1890,13 @@ pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Txs in success case (no refund) go as follows: /// Chain A: funding -> taker payment -> taker payment spend (aka preimage) (to the maker & dex) /// Chain B: maker payment -> maker payment spend (aka claiming) (to the taker) - async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + async fn get_funding_fee(&self, value: TradePreimageValue) -> TradePreimageResult; /// Get the fee to be paid for the processing of the taker payment transaction. - async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + async fn get_taker_payment_fee(&self) -> TradePreimageResult; /// Get the fee to be paid for the processing of the taker payment spend transaction aka the preimage transaction. - async fn get_taker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult; + async fn get_taker_payment_spend_fee(&self) -> TradePreimageResult; } /// Operations that coins have independently from the MarketMaker. diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 56250ae24e..9e1058129d 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -558,9 +558,9 @@ impl TakerCoinSwapOpsV2 for TestCoin { fn derive_htlc_pubkey_v2(&self, swap_unique_data: &[u8]) -> Self::Pubkey { todo!() } - async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + async fn get_funding_fee(&self, value: TradePreimageValue) -> TradePreimageResult { todo!() } - async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + async fn get_taker_payment_fee(&self) -> TradePreimageResult { todo!() } - async fn get_taker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { todo!() } + async fn get_taker_payment_spend_fee(&self) -> TradePreimageResult { todo!() } } diff --git a/mm2src/coins/utxo/utxo_common.rs b/mm2src/coins/utxo/utxo_common.rs index c095cf446d..96bf248830 100644 --- a/mm2src/coins/utxo/utxo_common.rs +++ b/mm2src/coins/utxo/utxo_common.rs @@ -884,26 +884,8 @@ enum FundingSpendFeeSetting { pub mod tx_sizes { use super::*; - /// Returns the taker funding transaction size in vbytes. - pub async fn get_funding_tx_size(_coin: &impl UtxoCommonOps) -> usize { - // This depends on what coins being spent so might be a bit clumsy. - // Since this is the first tx anyway, we won't need a utxo locking mechanism - // to prevent certain utxos from being spent in other swaps happening in parallel. - // We just need to make sure that we deliver the correct trading volume and not less. - - // FIXME: Inspect `get_sender_trade_fee`, but I don't think it nails it correctly. - todo!() - } - - /// Returns the maker payment transaction size in vbytes. - pub async fn get_maker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { - // Maker payment is similar to funding tx in that it spends coins directly from the user's - // wallet and sends them to P2SH address. - get_funding_tx_size(coin).await - } - /// Returns the taker payment transaction size in vbytes. - pub async fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { + pub fn get_taker_payment_tx_size(coin: &impl UtxoCommonOps) -> usize { let preimage = TransactionInputSigner { lock_time: 0, version: coin.as_ref().conf.tx_version, @@ -961,7 +943,7 @@ pub mod tx_sizes { } /// Returns the taker payment spend transaction size in vbytes. - pub async fn get_taker_payment_spend_tx_size(coin: &impl UtxoCommonOps) -> usize { + pub fn get_taker_payment_spend_tx_size(coin: &impl UtxoCommonOps) -> usize { let preimage = TransactionInputSigner { lock_time: 0, version: coin.as_ref().conf.tx_version, @@ -1022,7 +1004,7 @@ pub mod tx_sizes { } /// Returns the maker payment spend transaction size in vbytes. - pub async fn get_maker_payment_spend_tx_size(coin: &impl UtxoCommonOps) -> usize { + pub fn get_maker_payment_spend_tx_size(coin: &impl UtxoCommonOps) -> usize { let preimage = TransactionInputSigner { lock_time: 0, version: coin.as_ref().conf.tx_version, @@ -1213,12 +1195,7 @@ where let fee = match fee { FundingSpendFeeSetting::GetFromCoin => { - let calculated_fee = coin - .get_taker_payment_fee(&FeeApproxStage::WithoutApprox) - .await - .unwrap() - .amount - .to_decimal(); + let calculated_fee = coin.get_taker_payment_fee().await.unwrap().amount.to_decimal(); let calculated_fee = sat_from_big_decimal(&calculated_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; let taker_instructed_fee = sat_from_big_decimal(&args.taker_payment_fee, coin.as_ref().decimals).mm_err(|e| e.into())?; diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 6086728af4..f058df72ca 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -651,21 +651,16 @@ impl MakerCoinSwapOpsV2 for UtxoStandardCoin { utxo_common::spend_maker_payment_v2(self, args).await } - async fn get_maker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { - let maker_payment_tx_size = utxo_common::tx_sizes::get_maker_payment_tx_size(self).await; - let fee_sat = self.get_htlc_spend_fee(maker_payment_tx_size as u64, stage).await?; - let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); - Ok(TradeFee { - coin: self.as_ref().conf.ticker.clone(), - amount, - paid_from_trading_vol: true, - }) + async fn get_maker_payment_fee(&self, value: TradePreimageValue) -> TradePreimageResult { + let mut fee = utxo_common::get_sender_trade_fee(self, value, FeeApproxStage::StartSwap).await?; + fee.paid_from_trading_vol = true; + Ok(fee) } - async fn get_maker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { - let maker_payment_spend_tx_size = utxo_common::tx_sizes::get_maker_payment_spend_tx_size(self).await; + async fn get_maker_payment_spend_fee(&self) -> TradePreimageResult { + let maker_payment_spend_tx_size = utxo_common::tx_sizes::get_maker_payment_spend_tx_size(self); let fee_sat = self - .get_htlc_spend_fee(maker_payment_spend_tx_size as u64, stage) + .get_htlc_spend_fee(maker_payment_spend_tx_size as u64, &FeeApproxStage::TradePreimage) .await?; let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); Ok(TradeFee { @@ -852,20 +847,17 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { *self.derive_htlc_key_pair(swap_unique_data).public() } - async fn get_funding_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { - let funding_tx_size = utxo_common::tx_sizes::get_funding_tx_size(self).await; - let fee_sat = self.get_htlc_spend_fee(funding_tx_size as u64, stage).await?; - let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); - Ok(TradeFee { - coin: self.as_ref().conf.ticker.clone(), - amount, - paid_from_trading_vol: true, - }) + async fn get_funding_fee(&self, value: TradePreimageValue) -> TradePreimageResult { + let mut fee = utxo_common::get_sender_trade_fee(self, value, FeeApproxStage::StartSwap).await?; + fee.paid_from_trading_vol = true; + Ok(fee) } - async fn get_taker_payment_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { - let taker_payment_tx_size = utxo_common::tx_sizes::get_taker_payment_tx_size(self).await; - let fee_sat = self.get_htlc_spend_fee(taker_payment_tx_size as u64, stage).await?; + async fn get_taker_payment_fee(&self) -> TradePreimageResult { + let taker_payment_tx_size = utxo_common::tx_sizes::get_taker_payment_tx_size(self); + let fee_sat = self + .get_htlc_spend_fee(taker_payment_tx_size as u64, &FeeApproxStage::TradePreimage) + .await?; let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); Ok(TradeFee { coin: self.as_ref().conf.ticker.clone(), @@ -874,10 +866,10 @@ impl TakerCoinSwapOpsV2 for UtxoStandardCoin { }) } - async fn get_taker_payment_spend_fee(&self, stage: &FeeApproxStage) -> TradePreimageResult { - let taker_payment_spend_tx_size = utxo_common::tx_sizes::get_taker_payment_spend_tx_size(self).await; + async fn get_taker_payment_spend_fee(&self) -> TradePreimageResult { + let taker_payment_spend_tx_size = utxo_common::tx_sizes::get_taker_payment_spend_tx_size(self); let fee_sat = self - .get_htlc_spend_fee(taker_payment_spend_tx_size as u64, stage) + .get_htlc_spend_fee(taker_payment_spend_tx_size as u64, &FeeApproxStage::TradePreimage) .await?; let amount = big_decimal_from_sat_unsigned(fee_sat, self.as_ref().decimals).into(); Ok(TradeFee { diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index cbeacb9ce3..235500966f 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -3,9 +3,9 @@ use super::{swap_v2_topic, LockedAmount, LockedAmountInfo, SavedTradeFee, SwapsC NEGOTIATION_TIMEOUT_SEC}; use crate::mm2::lp_swap::maker_swap::MakerSwapPreparedParams; use crate::mm2::lp_swap::swap_lock::SwapLock; +use crate::mm2::lp_swap::swap_v2_pb::*; use crate::mm2::lp_swap::{broadcast_swap_v2_msg_every, check_balance_for_maker_swap, recv_swap_v2_msg, SecretHashAlgo, SwapConfirmationsSettings, TransactionIdentifier, MAKER_SWAP_V2_TYPE, MAX_STARTED_AT_DIFF}; -use crate::mm2::lp_swap::{swap_v2_pb::*, NO_REFUND_FEE}; use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use coins::utxo::utxo_common::big_decimal_from_sat_unsigned; @@ -799,12 +799,7 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetMakerPaymentFee(e.to_string()); @@ -812,10 +807,10 @@ impl fee, Err(e) => { - let reason = AbortReason::FailedToGetTakerPaymentSpendFee(e.to_string()); + let reason = AbortReason::FailedToGetTakerPaymentFee(e.to_string()); return Self::change_state(Aborted::new(reason), state_machine).await; }, }; @@ -832,7 +827,7 @@ impl { diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index 6d491e74fd..3fe33ae28b 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -2,10 +2,10 @@ use super::swap_v2_common::*; use super::{LockedAmount, LockedAmountInfo, SavedTradeFee, SwapsContext, TakerSwapPreparedParams, NEGOTIATE_SEND_INTERVAL, NEGOTIATION_TIMEOUT_SEC}; use crate::mm2::lp_swap::swap_lock::SwapLock; +use crate::mm2::lp_swap::swap_v2_pb::*; use crate::mm2::lp_swap::{broadcast_swap_v2_msg_every, check_balance_for_taker_swap, recv_swap_v2_msg, swap_v2_topic, SecretHashAlgo, SwapConfirmationsSettings, TransactionIdentifier, MAX_STARTED_AT_DIFF, TAKER_SWAP_V2_TYPE}; -use crate::mm2::lp_swap::{swap_v2_pb::*, NO_REFUND_FEE}; use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; use coins::utxo::sat_from_big_decimal; @@ -940,11 +940,9 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetTakerPaymentSpendFee(e.to_string()); @@ -952,16 +950,12 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetTakerPaymentFee(e.to_string()); @@ -969,7 +963,7 @@ impl fee, Err(e) => { let reason = AbortReason::FailedToGetMakerPaymentSpendFee(e.to_string()); @@ -999,7 +993,7 @@ impl