diff --git a/CHANGELOG.md b/CHANGELOG.md index 87b119268..bfbb18049 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Add capacity to create FeeRate from sats/kvbytes and sats/kwu. +- Rename `as_sat_vb` to `as_sat_per_vb`. Move all `FeeRate` test to `types.rs`. ## [v0.21.0] - [v0.20.0] @@ -19,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New `RpcBlockchain` implementation with various fixes. - Return balance in separate categories, namely `confirmed`, `trusted_pending`, `untrusted_pending` & `immature`. + ## [v0.20.0] - [v0.19.0] - New MSRV set to `1.56.1` diff --git a/src/types.rs b/src/types.rs index 5e54a3dcd..bae86477f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -63,6 +63,16 @@ impl FeeRate { FeeRate(value) } + /// Create a new instance of [`FeeRate`] given a float fee rate in sats/kwu + pub fn from_sat_per_kwu(sat_per_kwu: f32) -> Self { + FeeRate::new_checked(sat_per_kwu / 250.0_f32) + } + + /// Create a new instance of [`FeeRate`] given a float fee rate in sats/kvb + pub fn from_sat_per_kvb(sat_per_kvb: f32) -> Self { + FeeRate::new_checked(sat_per_kvb / 1000.0_f32) + } + /// Create a new instance of [`FeeRate`] given a float fee rate in btc/kvbytes /// /// ## Panics @@ -98,7 +108,7 @@ impl FeeRate { } /// Return the value as satoshi/vbyte - pub fn as_sat_vb(&self) -> f32 { + pub fn as_sat_per_vb(&self) -> f32 { self.0 } @@ -109,7 +119,7 @@ impl FeeRate { /// Calculate absolute fee in Satoshis using size in virtual bytes. pub fn fee_vb(&self, vbytes: usize) -> u64 { - (self.as_sat_vb() * vbytes as f32).ceil() as u64 + (self.as_sat_per_vb() * vbytes as f32).ceil() as u64 } } @@ -358,4 +368,34 @@ mod tests { fn test_valid_feerate_pos_zero() { let _ = FeeRate::from_sat_per_vb(0.0); } + + #[test] + fn test_fee_from_btc_per_kvb() { + let fee = FeeRate::from_btc_per_kvb(1e-5); + assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON); + } + + #[test] + fn test_fee_from_sat_per_vbyte() { + let fee = FeeRate::from_sat_per_vb(1.0); + assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON); + } + + #[test] + fn test_fee_default_min_relay_fee() { + let fee = FeeRate::default_min_relay_fee(); + assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON); + } + + #[test] + fn test_fee_from_sat_per_kvb() { + let fee = FeeRate::from_sat_per_kvb(1000.0); + assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON); + } + + #[test] + fn test_fee_from_sat_per_kwu() { + let fee = FeeRate::from_sat_per_kwu(250.0); + assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON); + } } diff --git a/src/wallet/coin_selection.rs b/src/wallet/coin_selection.rs index 0929bd1dd..702ba1855 100644 --- a/src/wallet/coin_selection.rs +++ b/src/wallet/coin_selection.rs @@ -454,7 +454,7 @@ impl CoinSelectionAlgorithm for BranchAndBoundCoinSelection { .iter() .fold(0, |acc, x| acc + x.effective_value); - let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_vb(); + let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_per_vb(); // `curr_value` and `curr_available_value` are both the sum of *effective_values* of // the UTXOs. For the optional UTXOs (curr_available_value) we filter out UTXOs with @@ -1360,7 +1360,8 @@ mod test { let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value); let size_of_change = 31; - let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb(); + let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb(); + let drain_script = Script::default(); let target_amount = 20_000 + FEE_AMOUNT; BranchAndBoundCoinSelection::new(size_of_change) @@ -1389,7 +1390,7 @@ mod test { let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value); let size_of_change = 31; - let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb(); + let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb(); let target_amount = 20_000 + FEE_AMOUNT; let drain_script = Script::default(); @@ -1413,7 +1414,7 @@ mod test { fn test_bnb_function_almost_exact_match_with_fees() { let fee_rate = FeeRate::from_sat_per_vb(1.0); let size_of_change = 31; - let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb(); + let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb(); let utxos: Vec<_> = generate_same_value_utxos(50_000, 10) .into_iter() diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index f7f7dc526..3506b1f5c 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -1067,7 +1067,7 @@ where utxos: original_utxos, bumping_fee: Some(tx_builder::PreviousFee { absolute: details.fee.ok_or(Error::FeeRateUnavailable)?, - rate: feerate.as_sat_vb(), + rate: feerate.as_sat_per_vb(), }), ..Default::default() }; @@ -2095,7 +2095,7 @@ pub(crate) mod test { let fee_rate = $fee_rate; if !dust_change { - assert!(tx_fee_rate >= fee_rate && (tx_fee_rate - fee_rate).as_sat_vb().abs() < 0.5, "Expected fee rate of {:?}, the tx has {:?}", fee_rate, tx_fee_rate); + assert!(tx_fee_rate >= fee_rate && (tx_fee_rate - fee_rate).as_sat_per_vb().abs() < 0.5, "Expected fee rate of {:?}, the tx has {:?}", fee_rate, tx_fee_rate); } else { assert!(tx_fee_rate >= fee_rate, "Expected fee rate of at least {:?}, the tx has {:?}", fee_rate, tx_fee_rate); } diff --git a/src/wallet/utils.rs b/src/wallet/utils.rs index cee72e40b..8c072da02 100644 --- a/src/wallet/utils.rs +++ b/src/wallet/utils.rs @@ -144,7 +144,6 @@ mod test { SEQUENCE_LOCKTIME_TYPE_FLAG, }; use crate::bitcoin::Address; - use crate::types::FeeRate; use std::str::FromStr; #[test] @@ -164,24 +163,6 @@ mod test { assert!(!294.is_dust(&script_p2wpkh)); } - #[test] - fn test_fee_from_btc_per_kb() { - let fee = FeeRate::from_btc_per_kvb(1e-5); - assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001); - } - - #[test] - fn test_fee_from_sats_vbyte() { - let fee = FeeRate::from_sat_per_vb(1.0); - assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001); - } - - #[test] - fn test_fee_default_min_relay_fee() { - let fee = FeeRate::default_min_relay_fee(); - assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001); - } - #[test] fn test_check_nsequence_rbf_msb_set() { let result = check_nsequence_rbf(0x80000000, 5000);