diff --git a/src/maker/api.rs b/src/maker/api.rs index 523bdf4f..e2f6ce17 100644 --- a/src/maker/api.rs +++ b/src/maker/api.rs @@ -49,9 +49,51 @@ use crate::{ use super::{config::MakerConfig, error::MakerError}; -use crate::maker::server::{ - HEART_BEAT_INTERVAL_SECS, MIN_CONTRACT_REACTION_TIME, REQUIRED_CONFIRMS, -}; +/// The core server process interval. many of the maker server's internal threads "beats" at this frequency. +pub const HEART_BEAT_INTERVAL_SECS: u64 = 3; + +/// RPC Backend health check interval. +pub const RPC_PING_INTERVAL_SECS: u64 = 60; + +// Currently we don't refresh address at DNS. The Maker only post it once at startup. +// If the address record gets deleted, or the DNS gets blasted, the Maker won't know. +// TODO: Make the maker repost their address to DNS once a day in spawned thread. +// pub const DIRECTORY_SERVERS_REFRESH_INTERVAL_SECS: u64 = 60 * 60 * 24; // Once a day. + +/// Maker triggers the recovery mechanism, if Taker is idle for more than 300 secs. +pub const IDLE_CONNECTION_TIMEOUT: Duration = Duration::from_secs(300); + +/// Number of confirmation required funding transaction. +pub const REQUIRED_CONFIRMS: u64 = 1; + +/// The minimum locktime difference between the incoming and outgoing swaps. +/// This is the reaction time in blocks a Maker has to claim his refund transaction, in case of recovery. +/// Bolt2 has an estimate of minimum `cltv_expiry_delta` as 18 blocks. https://github.com/lightning/bolts/blob/aa5207aeaa32d841353dd2df3ce725a4046d528d/02-peer-protocol.md?plain=1#L1798 +/// To be a bit more conservative we use 20 as the default value. +pub const MIN_CONTRACT_REACTION_TIME: u16 = 20; + +/// Fee Parameters +/// +/// abs_fee = Constant fee for all swaps. +/// amount_relative_fee = Percentage fee relative to the swap_amount. +/// time_relative_fee = Percentage fee applied to the refund_locktime, i.e, how long the maker needs to wait for their refund time-lock. +/// +/// Increasing the swap amount and refund timelock, increases the coinswap fee, claimed by the maker. +/// Check [REFUND_LOCKTIME] and [REFUND_LOCKTIME_STEP] of taker::api.rs. +/// +/// So Total fee on swap is calculated as +/// `total_fee = abs_fee + (swap_amount * relative_fee)/100 + (swap_amount * refund_locktime * time_relative_fee)/100`; +/// +/// # Example for default values: +/// For swap_amount = 100,000 sats, refund_locktime = 20 Blocks; +/// abs_fee = 1000 sats; +/// amount_relative_fee = (100,000 * 2.5)/100 = 2500 sats; +/// time_relative_fee = (100,000 * 20 * 0.1)/100 = 2000 sats; +/// total_fee = 5500 sats, i.e. 5.5%; +/// The fee rates are set such a way, that the total % fees reaches 5% asymptotically with increase in swap amount. +pub const ABSOLUTE_FEE: u64 = 1000; +pub const AMOUNT_RELATIVE_FEE: f64 = 2.50; +pub const TIME_RELATIVE_FEE: f64 = 0.10; /// Used to configure the maker for testing purposes. #[derive(Debug, Clone, Copy)] @@ -285,7 +327,7 @@ impl Maker { // check that the new locktime is sufficently short enough compared to the // locktime in the provided funding tx let locktime = read_contract_locktime(&funding_info.contract_redeemscript)?; - if locktime - message.next_locktime < MIN_CONTRACT_REACTION_TIME { + if locktime - message.refund_locktime < MIN_CONTRACT_REACTION_TIME { return Err(MakerError::General( "Next hop locktime too close to current hop locktime", )); @@ -560,7 +602,7 @@ pub fn check_for_idle_states(maker: Arc) -> Result<(), MakerError> { ip, no_response_since ); - if no_response_since > std::time::Duration::from_secs(60) { + if no_response_since > IDLE_CONNECTION_TIMEOUT { log::error!( "[{}] Potential Dropped Connection from {}", maker.config.port, diff --git a/src/maker/config.rs b/src/maker/config.rs index a3a85844..92990daa 100644 --- a/src/maker/config.rs +++ b/src/maker/config.rs @@ -3,7 +3,6 @@ use crate::utill::parse_toml; use std::{io, path::PathBuf}; -use bitcoin::Amount; use std::io::Write; use crate::utill::{get_maker_dir, parse_field, ConnectionType}; @@ -15,13 +14,8 @@ pub struct MakerConfig { pub port: u16, /// RPC listening port pub rpc_port: u16, - /// Absolute coinswap fee - pub absolute_fee_sats: Amount, - /// Fee rate for timelocked contract in parts per billion (PPB). - /// Similar to `DEFAULT_AMOUNT_RELATIVE_FEE_PPB`, calculated as (amount * fee_ppb) / 1_000_000_000. - pub time_relative_fee_ppb: Amount, - /// Minimum timelock difference between contract transaction of two hops - pub min_size: u64, + /// Minimum swap size. + pub min_swap_amount: u64, /// Socks port pub socks_port: u16, /// Directory server address (can be clearnet or onion) @@ -39,9 +33,7 @@ impl Default for MakerConfig { Self { port: 6102, rpc_port: 6103, - absolute_fee_sats: Amount::from_sat(1000), - time_relative_fee_ppb: Amount::from_sat(100_000), - min_size: 10_000, + min_swap_amount: 100_000, // A swap amount lower than this will not be economical. socks_port: 19050, directory_server_address: "directoryhiddenserviceaddress.onion:8080".to_string(), fidelity_value: 5_000_000, // 5 million sats @@ -88,21 +80,15 @@ impl MakerConfig { Ok(MakerConfig { port: parse_field(config_map.get("port"), default_config.port), rpc_port: parse_field(config_map.get("rpc_port"), default_config.rpc_port), - absolute_fee_sats: parse_field( - config_map.get("absolute_fee_sats"), - default_config.absolute_fee_sats, + min_swap_amount: parse_field( + config_map.get("min_swap_amount"), + default_config.min_swap_amount, ), - time_relative_fee_ppb: parse_field( - config_map.get("time_relative_fee_ppb"), - default_config.time_relative_fee_ppb, - ), - min_size: parse_field(config_map.get("min_size"), default_config.min_size), socks_port: parse_field(config_map.get("socks_port"), default_config.socks_port), directory_server_address: parse_field( config_map.get("directory_server_address"), default_config.directory_server_address, ), - fidelity_value: parse_field( config_map.get("fidelity_value"), default_config.fidelity_value, @@ -122,20 +108,16 @@ impl MakerConfig { pub fn write_to_file(&self, path: &PathBuf) -> std::io::Result<()> { let toml_data = format!( "port = {} -rpc_port = {} -absolute_fee_sats = {} -time_relative_fee_ppb = {} -min_size = {} -socks_port = {} -directory_server_address = {} -fidelity_value = {} -fidelity_timelock = {} -connection_type = {:?}", + rpc_port = {} + min_swap_amount = {} + socks_port = {} + directory_server_address = {} + fidelity_value = {} + fidelity_timelock = {} + connection_type = {:?}", self.port, self.rpc_port, - self.absolute_fee_sats, - self.time_relative_fee_ppb, - self.min_size, + self.min_swap_amount, self.socks_port, self.directory_server_address, self.fidelity_value, @@ -177,12 +159,9 @@ mod tests { [maker_config] port = 6102 rpc_port = 6103 - absolute_fee_sats = 1000 - amount_relative_fee_ppb = 10000000 - time_relative_fee_ppb = 100000 required_confirms = 1 min_contract_reaction_time = 48 - min_size = 10000 + min_swap_amount = 10000 socks_port = 19050 "#; let config_path = create_temp_config(contents, "valid_maker_config.toml"); diff --git a/src/maker/handlers.rs b/src/maker/handlers.rs index 647138d3..e4548601 100644 --- a/src/maker/handlers.rs +++ b/src/maker/handlers.rs @@ -17,8 +17,9 @@ use bitcoin::{ use bitcoind::bitcoincore_rpc::RpcApi; use crate::{ - maker::api::recover_from_swap, + maker::api::{recover_from_swap, ABSOLUTE_FEE, AMOUNT_RELATIVE_FEE, TIME_RELATIVE_FEE}, protocol::{ + contract::calculate_coinswap_fee, error::ProtocolError, messages::{MakerHello, MultisigPrivkey, PrivKeyHandover}, Hash160, @@ -33,8 +34,7 @@ use crate::{ }, protocol::{ contract::{ - calculate_coinswap_fee, create_receivers_contract_tx, find_funding_output_index, - read_contract_locktime, read_hashvalue_from_contract, + create_receivers_contract_tx, find_funding_output_index, read_hashvalue_from_contract, read_pubkeys_from_multisig_redeemscript, FUNDING_TX_VBYTE_SIZE, }, messages::{ @@ -47,9 +47,8 @@ use crate::{ wallet::{IncomingSwapCoin, SwapCoin}, }; -use crate::maker::server::{ - AMOUNT_RELATIVE_FEE_PPB, MIN_CONTRACT_REACTION_TIME, REQUIRED_CONFIRMS, -}; +use super::api::{MIN_CONTRACT_REACTION_TIME, REQUIRED_CONFIRMS}; + /// The Global Handle Message function. Takes in a [`Arc`] and handle messages /// according to a [ConnectionState]. pub fn handle_message( @@ -96,13 +95,13 @@ pub fn handle_message( let fidelity = maker.highest_fidelity_proof.read()?; let fidelity = fidelity.as_ref().expect("proof expected"); Some(MakerToTakerMessage::RespOffer(Box::new(Offer { - absolute_fee_sat: maker.config.absolute_fee_sats, - amount_relative_fee_ppb: AMOUNT_RELATIVE_FEE_PPB, - time_relative_fee_ppb: maker.config.time_relative_fee_ppb, + absolute_fee: ABSOLUTE_FEE, + amount_relative_fee: AMOUNT_RELATIVE_FEE, + time_relative_fee: TIME_RELATIVE_FEE, required_confirms: REQUIRED_CONFIRMS, minimum_locktime: MIN_CONTRACT_REACTION_TIME, max_size, - min_size: maker.config.min_size, + min_size: maker.config.min_swap_amount, tweakable_point, fidelity: fidelity.clone(), }))) @@ -241,7 +240,7 @@ impl Maker { acc + txinfo.funding_input_value.to_sat() }); - if total_funding_amount >= self.config.min_size + if total_funding_amount >= self.config.min_swap_amount && total_funding_amount < self.wallet.read()?.store.offer_maxsize { log::info!( @@ -300,7 +299,7 @@ impl Maker { }, funding_output.value, &funding_info.contract_redeemscript, - Amount::from_sat(message.next_fee_rate), + Amount::from_sat(message.contract_feerate), )?; let (tweakable_privkey, _) = self.wallet.read()?.get_tweakable_keypair()?; @@ -359,19 +358,30 @@ impl Maker { })?; let calc_coinswap_fees = calculate_coinswap_fee( - self.config.absolute_fee_sats, - AMOUNT_RELATIVE_FEE_PPB, - self.config.time_relative_fee_ppb, - Amount::from_sat(incoming_amount), - REQUIRED_CONFIRMS, //time_in_blocks just 1 for now + incoming_amount, + message.refund_locktime, + ABSOLUTE_FEE, + AMOUNT_RELATIVE_FEE, + TIME_RELATIVE_FEE, ); let calc_funding_tx_fees = (FUNDING_TX_VBYTE_SIZE - * message.next_fee_rate + * message.contract_feerate * (message.next_coinswap_info.len() as u64)) / 1000; - let outgoing_amount = incoming_amount - calc_coinswap_fees - calc_funding_tx_fees; + // Check for overflow. If happens hard error. + // This can happen if the fee_rate for funding tx is very high and incoming_amount is very low. + // TODO: Ensure at Taker protocol that this never happens. + let outgoing_amount = if let Some(a) = + incoming_amount.checked_sub(calc_coinswap_fees + calc_funding_tx_fees) + { + a + } else { + return Err(MakerError::General( + "Fatal Error! Total swap fee is more than the swap amount. Failing the swap.", + )); + }; // Create outgoing coinswap of the next hop let (my_funding_txes, outgoing_swapcoins, act_funding_txs_fees) = { @@ -388,12 +398,14 @@ impl Maker { .map(|next_hop| next_hop.next_hashlock_pubkey) .collect::>(), hashvalue, - message.next_locktime, - Amount::from_sat(message.next_fee_rate), + message.refund_locktime, + Amount::from_sat(message.contract_feerate), )? }; - let act_coinswap_fees = incoming_amount - outgoing_amount - act_funding_txs_fees.to_sat(); + let act_coinswap_fees = incoming_amount + .checked_sub(outgoing_amount + act_funding_txs_fees.to_sat()) + .expect("This should not overflow as we just above."); log::info!( "[{}] Outgoing Funding Txids: {:?}.", @@ -403,27 +415,18 @@ impl Maker { .map(|tx| tx.compute_txid()) .collect::>() ); - log::debug!( - "[{}] Outgoing Swapcoins: {:?}.", - self.config.port, - outgoing_swapcoins - ); log::info!( - "incoming_amount = {} | incoming_locktime = {} | outgoing_amount = {} | outgoing_locktime = {}", + "Incoming Swap Amount = {} | Outgoing Swap Amount = {} | Swap Revenue = {}", Amount::from_sat(incoming_amount), - read_contract_locktime( - &message.confirmed_funding_txes[0].contract_redeemscript - )?, Amount::from_sat(outgoing_amount), - message.next_locktime + Amount::from_sat(act_coinswap_fees) ); + log::info!( - "Calculated Funding Txs Fees = {} | Actual Funding Txs Fees = {} | Calculated Swap Revenue = {} | Actual Swap Revenue = {}", - Amount::from_sat(calc_funding_tx_fees), - act_funding_txs_fees, - Amount::from_sat(calc_coinswap_fees), - Amount::from_sat(act_coinswap_fees) + "Our Refund Tx locktime (blocks) = {} | Total Funding Tx Mining Fees = {} | ", + message.refund_locktime, + act_funding_txs_fees ); connection_state.pending_funding_txes = my_funding_txes; diff --git a/src/maker/server.rs b/src/maker/server.rs index b247b18e..35b0c3f6 100644 --- a/src/maker/server.rs +++ b/src/maker/server.rs @@ -22,6 +22,7 @@ use bitcoind::bitcoincore_rpc::RpcApi; use socks::Socks5Stream; +use super::api::{HEART_BEAT_INTERVAL_SECS, RPC_PING_INTERVAL_SECS}; pub use super::Maker; use crate::{ @@ -38,18 +39,6 @@ use crate::{ use crate::maker::error::MakerError; -// Default values for Maker configurations -pub const HEART_BEAT_INTERVAL_SECS: u64 = 3; -pub const RPC_PING_INTERVAL_SECS: u64 = 60; -pub const _DIRECTORY_SERVERS_REFRESH_INTERVAL_SECS: u64 = 60 * 60 * 12; // 12 Hours -pub const _IDLE_CONNECTION_TIMEOUT: u64 = 300; -pub const REQUIRED_CONFIRMS: u64 = 1; -pub const MIN_CONTRACT_REACTION_TIME: u16 = 48; - -/// Fee rate per swap amount in parts per billion (PPB). -/// E.g., for 1 billion sats (0.01 BTC), a value of 10_000 would result in a 0.1% fee. -pub const AMOUNT_RELATIVE_FEE_PPB: Amount = Amount::from_sat(10_000_000); - /// Fetches the Maker and DNS address, and sends maker address to the DNS server. /// Depending upon ConnectionType and test/prod environment, different maker address and DNS addresses are returned. /// Return the Maker address and an optional tor thread handle. @@ -419,8 +408,6 @@ pub fn start_maker_server(maker: Arc) -> Result<(), MakerError> { maker_address ); - let heart_beat_interval = HEART_BEAT_INTERVAL_SECS; // All maker internal threads loops at this frequency. - // Setup the wallet with fidelity bond. let network = maker.get_wallet().read()?.store.network; let balance = maker.get_wallet().read()?.balance()?; @@ -502,7 +489,7 @@ pub fn start_maker_server(maker: Arc) -> Result<(), MakerError> { maker.thread_pool.add_thread(rpc_thread); - sleep(Duration::from_secs(heart_beat_interval)); // wait for 1 beat, to complete spawns of all the threads. + sleep(Duration::from_secs(HEART_BEAT_INTERVAL_SECS)); // wait for 1 beat, to complete spawns of all the threads. maker.is_setup_complete.store(true, Relaxed); log::info!("[{}] Maker setup is ready", maker.config.port); } diff --git a/src/protocol/contract.rs b/src/protocol/contract.rs index e94e244b..654a85d3 100644 --- a/src/protocol/contract.rs +++ b/src/protocol/contract.rs @@ -54,16 +54,19 @@ const PUBKEY1_OFFSET: usize = 2; const PUBKEY2_OFFSET: usize = PUBKEY1_OFFSET + PUBKEY_LENGTH + 1; /// Calculate the coin swap fee based on various parameters. +/// swap_amount in sats, refund_locktime in blocks. pub fn calculate_coinswap_fee( - absolute_fee_sat: Amount, - amount_relative_fee_ppb: Amount, - time_relative_fee_ppb: Amount, - total_funding_amount: Amount, - time_in_blocks: u64, + swap_amount: u64, + refund_locktime: u16, + abs_fee: u64, + amt_rel_fee: f64, + time_rel_fee: f64, ) -> u64 { - absolute_fee_sat.to_sat() - + (total_funding_amount.to_sat() * amount_relative_fee_ppb.to_sat()) / 1_000_000_000 - + (time_in_blocks * time_relative_fee_ppb.to_sat()) / 1_000_000_000 + let total_fee = abs_fee as f64 + + (swap_amount as f64 * amt_rel_fee) / 1_00.00 + + (swap_amount as f64 * refund_locktime as f64 * time_rel_fee) / 1_00.00; + + total_fee.ceil() as u64 } /// Apply two signatures to a 2-of-2 multisig spend. @@ -1092,54 +1095,46 @@ mod test { #[test] fn calculate_coinswap_fee_normal() { // Test with typical values - let absolute_fee_sat = Amount::from_sat(1000); - let amount_relative_fee_ppb = Amount::from_sat(500_000_000); - let time_relative_fee_ppb = Amount::from_sat(200_000_000); - let total_funding_amount = Amount::from_sat(1_000_000_000); - let time_in_blocks = 100; + let absolute_fee_sat = 1000; + let amount_rel_fee = 2.5; + let time_rel_fee = 0.1; + let swap_amount = 100_000; + let refund_locktime = 20; - let expected_fee = 1000 - + (1_000_000_000 * 500_000_000) / 1_000_000_000 - + (100 * 200_000_000) / 1_000_000_000; + let expected_fee = 5500; let calculated_fee = calculate_coinswap_fee( + swap_amount, + refund_locktime, absolute_fee_sat, - amount_relative_fee_ppb, - time_relative_fee_ppb, - total_funding_amount, - time_in_blocks, + amount_rel_fee, + time_rel_fee, ); assert_eq!(calculated_fee, expected_fee); // Test with zero values assert_eq!( - calculate_coinswap_fee(Amount::ZERO, Amount::ZERO, Amount::ZERO, Amount::ZERO, 0), + calculate_coinswap_fee(swap_amount, refund_locktime, 0, 0.0, 0.0), 0 ); // Test with only the absolute fee being non-zero assert_eq!( - calculate_coinswap_fee( - Amount::from_sat(1000), - Amount::ZERO, - Amount::ZERO, - Amount::ZERO, - 0 - ), + calculate_coinswap_fee(swap_amount, refund_locktime, absolute_fee_sat, 0.0, 0.0), 1000 ); // Test with only the relative fees being non-zero assert_eq!( calculate_coinswap_fee( - Amount::ZERO, - Amount::from_sat(1_000_000_000), - Amount::from_sat(1_000_000_000), - Amount::from_sat(1000), - 10 + swap_amount, + refund_locktime, + 0, + amount_rel_fee, + time_rel_fee ), - 1010 + 4500 ); } @@ -1292,8 +1287,8 @@ mod test { next_hashlock_pubkey: pub_1, next_multisig_pubkey: pub_2, }], - next_locktime: u16::default(), - next_fee_rate: u64::default(), + refund_locktime: u16::default(), + contract_feerate: u64::default(), }; // case with same hash value @@ -1321,8 +1316,8 @@ mod test { next_hashlock_pubkey: pub_1, next_multisig_pubkey: pub_2, }], - next_locktime: u16::default(), - next_fee_rate: u64::default(), + refund_locktime: u16::default(), + contract_feerate: u64::default(), }; let hash_value_from_fn = check_hashvalues_are_equal(&funding_proof).unwrap_err(); diff --git a/src/protocol/messages.rs b/src/protocol/messages.rs index 400ea6ef..8c712157 100644 --- a/src/protocol/messages.rs +++ b/src/protocol/messages.rs @@ -142,8 +142,8 @@ pub struct ProofOfFunding { pub confirmed_funding_txes: Vec, // TODO: Directly use Vec of Pubkeys. pub next_coinswap_info: Vec, - pub next_locktime: u16, - pub next_fee_rate: u64, + pub refund_locktime: u16, + pub contract_feerate: u64, } /// Signatures required for an intermediate Maker to perform receiving and sending of coinswaps. @@ -236,11 +236,11 @@ pub struct FidelityProof { } /// Represents an offer in the context of the Coinswap protocol. -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Hash)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, PartialOrd)] pub struct Offer { - pub absolute_fee_sat: Amount, - pub amount_relative_fee_ppb: Amount, - pub time_relative_fee_ppb: Amount, + pub absolute_fee: u64, // base fee in sats + pub amount_relative_fee: f64, // % fee on total amount + pub time_relative_fee: f64, // amount * refund_locktime * TRF% = fees for locking the fund. pub required_confirms: u64, pub minimum_locktime: u16, pub max_size: u64, @@ -283,7 +283,7 @@ pub struct ContractSigsForRecvr { } /// All messages sent from Maker to Taker. -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Debug, Serialize, Deserialize, PartialEq)] pub enum MakerToTakerMessage { /// Protocol Handshake. MakerHello(MakerHello), diff --git a/src/taker/api.rs b/src/taker/api.rs index 50701515..71fe5992 100644 --- a/src/taker/api.rs +++ b/src/taker/api.rs @@ -82,7 +82,12 @@ pub struct SwapParams { // TODO: Following two should be moved to TakerConfig as global configuration. /// Confirmation count required for funding txs. pub required_confirms: u64, - /// Fee rate for funding txs. + + /// Fee rate for funding and contract txs. + // TODO: This fee rate should be decided by the Makers. + // Taker can DOS makers by forcing them to recover at high fee environment, while keeping fee rate low. + // Its difficult to decide what should be the correct feerate, and maker's should have some type of fee estimation + // mechanism to set this fee dynamically. pub fee_rate: Amount, } @@ -966,18 +971,19 @@ impl Taker { log::info!("Fundix Txids: {:?}", funding_txids); // Struct for information related to the next peer - let next_maker_info = NextPeerInfoArgs { + let next_maker_info = NextMakerInfo { next_peer_multisig_pubkeys: next_peer_multisig_pubkeys.clone(), next_peer_hashlock_pubkeys: next_peer_hashlock_pubkeys.clone(), - next_maker_refund_locktime: maker_refund_locktime, - next_maker_fee_rate: self.ongoing_swap_state.swap_params.fee_rate, }; let this_maker_info = ThisMakerInfo { this_maker: this_maker.clone(), funding_tx_infos: funding_tx_infos.to_vec(), this_maker_contract_txs, + this_maker_refund_locktime: maker_refund_locktime, + this_maker_fee_rate: self.ongoing_swap_state.swap_params.fee_rate, }; + let (contract_sigs_as_recvr_sender, next_swap_contract_redeemscripts) = send_proof_of_funding_and_init_next_hop( &mut socket, diff --git a/src/taker/offers.rs b/src/taker/offers.rs index 68474fdc..981024d1 100644 --- a/src/taker/offers.rs +++ b/src/taker/offers.rs @@ -26,7 +26,7 @@ use crate::{ use super::{config::TakerConfig, error::TakerError, routines::download_maker_offer}; /// Represents an offer along with the corresponding maker address. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct OfferAndAddress { pub offer: Offer, pub address: MakerAddress, diff --git a/src/taker/routines.rs b/src/taker/routines.rs index ceba3b7d..bcc903df 100644 --- a/src/taker/routines.rs +++ b/src/taker/routines.rs @@ -244,22 +244,22 @@ pub struct ThisMakerInfo { pub this_maker: OfferAndAddress, pub funding_tx_infos: Vec, pub this_maker_contract_txs: Vec, + pub this_maker_refund_locktime: u16, + pub this_maker_fee_rate: Amount, // Applies to both funding and contract transaction } // Type for information related to the next peer #[derive(Clone)] -pub struct NextPeerInfoArgs { +pub struct NextMakerInfo { pub next_peer_multisig_pubkeys: Vec, pub next_peer_hashlock_pubkeys: Vec, - pub next_maker_refund_locktime: u16, - pub next_maker_fee_rate: Amount, } /// [Internal] Send a Proof funding to the maker and init next hop. pub(crate) fn send_proof_of_funding_and_init_next_hop( socket: &mut TcpStream, tmi: ThisMakerInfo, - npi: NextPeerInfoArgs, + npi: NextMakerInfo, hashvalue: Hash160, ) -> Result<(ContractSigsAsRecvrAndSender, Vec), TakerError> { // Send POF @@ -278,8 +278,8 @@ pub(crate) fn send_proof_of_funding_and_init_next_hop( let pof_msg = TakerToMakerMessage::RespProofOfFunding(ProofOfFunding { confirmed_funding_txes: tmi.funding_tx_infos.clone(), next_coinswap_info, - next_locktime: npi.next_maker_refund_locktime, - next_fee_rate: npi.next_maker_fee_rate.to_sat(), + refund_locktime: tmi.this_maker_refund_locktime, + contract_feerate: tmi.this_maker_fee_rate.to_sat(), }); send_message(socket, &pof_msg)?; @@ -336,15 +336,17 @@ pub(crate) fn send_proof_of_funding_and_init_next_hop( .iter() .map(|i| i.funding_amount) .sum::(); + let coinswap_fees = calculate_coinswap_fee( - tmi.this_maker.offer.absolute_fee_sat, - tmi.this_maker.offer.amount_relative_fee_ppb, - tmi.this_maker.offer.time_relative_fee_ppb, - Amount::from_sat(this_amount), - 1, //time_in_blocks just 1 for now + this_amount, + tmi.this_maker_refund_locktime, + tmi.this_maker.offer.absolute_fee, + tmi.this_maker.offer.amount_relative_fee, + tmi.this_maker.offer.time_relative_fee, ); + let miner_fees_paid_by_taker = (FUNDING_TX_VBYTE_SIZE - * npi.next_maker_fee_rate.to_sat() + * tmi.this_maker_fee_rate.to_sat() * (npi.next_peer_multisig_pubkeys.len() as u64)) / 1000; let calculated_next_amount = this_amount - coinswap_fees - miner_fees_paid_by_taker; @@ -356,7 +358,7 @@ pub(crate) fn send_proof_of_funding_and_init_next_hop( .into()); } log::info!( - "this_amount={} coinswap_fees={} miner_fees_paid_by_taker={} next_amount={}", + "Next maker's amount = {} | Next maker's fees = {} | Miner fees covered by us = {} | Maker is forwarding = {}", this_amount, coinswap_fees, miner_fees_paid_by_taker, @@ -393,7 +395,7 @@ pub(crate) fn send_proof_of_funding_and_init_next_hop( hashlock_pubkey, &senders_contract_tx_info.timelock_pubkey, &hashvalue, - &npi.next_maker_refund_locktime, + &tmi.this_maker_refund_locktime, ) }) .collect::>();