@@ -148,6 +148,59 @@ impl OnchainPayment {
148148 Ok ( selected_utxos)
149149 }
150150
151+ /// Calculates the total fee for an on-chain payment without sending it.
152+ ///
153+ /// This method simulates creating a transaction to the given address for the specified amount
154+ /// and returns the total fee that would be paid. This is useful for displaying fee estimates
155+ /// to users before they confirm a transaction.
156+ ///
157+ /// The calculation respects any on-chain reserve requirements and validates that sufficient
158+ /// funds are available, just like [`send_to_address`].
159+ ///
160+ /// # Arguments
161+ ///
162+ /// * `address` - The Bitcoin address to send to
163+ /// * `amount_sats` - The amount to send in satoshis
164+ /// * `fee_rate` - Optional fee rate to use (if None, will estimate based on current network conditions)
165+ /// * `utxos_to_spend` - Optional list of specific UTXOs to use for the transaction
166+ ///
167+ /// # Returns
168+ ///
169+ /// The total fee in satoshis that would be paid for this transaction.
170+ ///
171+ /// # Errors
172+ ///
173+ /// * [`Error::NotRunning`] - If the node is not running
174+ /// * [`Error::InvalidAddress`] - If the address is invalid
175+ /// * [`Error::InsufficientFunds`] - If there are insufficient funds for the payment
176+ /// * [`Error::WalletOperationFailed`] - If fee calculation fails
177+ ///
178+ /// [`send_to_address`]: Self::send_to_address
179+ pub fn calculate_total_fee (
180+ & self , address : & bitcoin:: Address , amount_sats : u64 , fee_rate : Option < FeeRate > ,
181+ utxos_to_spend : Option < Vec < SpendableUtxo > > ,
182+ ) -> Result < u64 , Error > {
183+ let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
184+ if rt_lock. is_none ( ) {
185+ return Err ( Error :: NotRunning ) ;
186+ }
187+
188+ let cur_anchor_reserve_sats =
189+ crate :: total_anchor_channels_reserve_sats ( & self . channel_manager , & self . config ) ;
190+ let send_amount =
191+ OnchainSendAmount :: ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats } ;
192+ let outpoints = utxos_to_spend. map ( |utxos| utxos. into_iter ( ) . map ( |u| u. outpoint ) . collect ( ) ) ;
193+ let fee_rate_opt = maybe_map_fee_rate_opt ! ( fee_rate) ;
194+
195+ self . wallet . calculate_transaction_fee (
196+ address,
197+ send_amount,
198+ fee_rate_opt,
199+ outpoints,
200+ & self . channel_manager ,
201+ )
202+ }
203+
151204 /// Send an on-chain payment to the given address.
152205 ///
153206 /// This will respect any on-chain reserve we need to keep, i.e., won't allow to cut into
@@ -325,7 +378,9 @@ impl OnchainPayment {
325378 /// * [`Error::TransactionNotFound`] - If the parent transaction can't be found
326379 /// * [`Error::TransactionAlreadyConfirmed`] - If the parent transaction is already confirmed
327380 /// * [`Error::WalletOperationFailed`] - If fee calculation fails
328- pub fn calculate_cpfp_fee_rate ( & self , parent_txid : & Txid , urgent : bool ) -> Result < FeeRate , Error > {
381+ pub fn calculate_cpfp_fee_rate (
382+ & self , parent_txid : & Txid , urgent : bool ,
383+ ) -> Result < FeeRate , Error > {
329384 let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
330385 if rt_lock. is_none ( ) {
331386 return Err ( Error :: NotRunning ) ;
0 commit comments