@@ -13,7 +13,7 @@ use arbitrary::{Arbitrary, Unstructured};
1313
1414use NumOpResult as R ;
1515
16- use crate :: { Amount , MathOp , NumOpError as E , NumOpResult } ;
16+ use crate :: { Amount , MathOp , NumOpError as E , NumOpResult , Weight } ;
1717
1818mod encapsulate {
1919 /// Fee rate.
@@ -184,6 +184,62 @@ impl FeeRate {
184184 None => None ,
185185 }
186186 }
187+
188+ /// Calculates the fee by multiplying this fee rate by weight.
189+ ///
190+ /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting
191+ /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is
192+ /// enough instead of falling short if rounded down.
193+ ///
194+ /// If the calculation would overflow we saturate to [`Amount::MAX`]. Since such a fee can never
195+ /// be paid this is meaningful as an error case while still removing the possibility of silently
196+ /// wrapping.
197+ pub const fn to_fee ( self , weight : Weight ) -> Amount {
198+ // No `unwrap_or()` in const context.
199+ match self . checked_mul_by_weight ( weight) {
200+ Some ( fee) => fee,
201+ None => Amount :: MAX ,
202+ }
203+ }
204+
205+ /// Calculates the fee by multiplying this fee rate by weight, in weight units, returning [`None`]
206+ /// if an overflow occurred.
207+ ///
208+ /// This is equivalent to `Self::checked_mul_by_weight()`.
209+ #[ must_use]
210+ #[ deprecated( since = "TBD" , note = "use `to_fee()` instead" ) ]
211+ pub fn fee_wu ( self , weight : Weight ) -> Option < Amount > { self . checked_mul_by_weight ( weight) }
212+
213+ /// Calculates the fee by multiplying this fee rate by weight, in virtual bytes, returning [`None`]
214+ /// if an overflow occurred.
215+ ///
216+ /// This is equivalent to converting `vb` to [`Weight`] using [`Weight::from_vb`] and then calling
217+ /// `Self::fee_wu(weight)`.
218+ #[ must_use]
219+ #[ deprecated( since = "TBD" , note = "use Weight::from_vb and then `to_fee()` instead" ) ]
220+ pub fn fee_vb ( self , vb : u64 ) -> Option < Amount > { Weight :: from_vb ( vb) . map ( |w| self . to_fee ( w) ) }
221+
222+ /// Checked weight multiplication.
223+ ///
224+ /// Computes the absolute fee amount for a given [`Weight`] at this fee rate. When the resulting
225+ /// fee is a non-integer amount, the amount is rounded up, ensuring that the transaction fee is
226+ /// enough instead of falling short if rounded down.
227+ ///
228+ /// Returns [`None`] if overflow occurred.
229+ #[ must_use]
230+ pub const fn checked_mul_by_weight ( self , weight : Weight ) -> Option < Amount > {
231+ let wu = weight. to_wu ( ) ;
232+ if let Some ( fee_kwu) = self . to_sat_per_kwu_floor ( ) . checked_mul ( wu) {
233+ // Bump by 999 to do ceil division using kwu.
234+ if let Some ( bump) = fee_kwu. checked_add ( 999 ) {
235+ let fee = bump / 1_000 ;
236+ if let Ok ( fee_amount) = Amount :: from_sat ( fee) {
237+ return Some ( fee_amount) ;
238+ }
239+ }
240+ }
241+ None
242+ }
187243}
188244
189245crate :: internal_macros:: impl_op_for_references! {
0 commit comments