@@ -157,10 +157,16 @@ impl OnchainPayment {
157157 /// The calculation respects any on-chain reserve requirements and validates that sufficient
158158 /// funds are available, just like [`send_to_address`].
159159 ///
160+ /// **Special handling for maximum amounts:** If the specified amount would result in
161+ /// insufficient funds due to fees, but is within the spendable balance, this method will
162+ /// automatically calculate the fee for sending all available funds while retaining the
163+ /// anchor channel reserve. This allows users to calculate fees when trying to send
164+ /// their maximum spendable balance.
165+ ///
160166 /// # Arguments
161167 ///
162168 /// * `address` - The Bitcoin address to send to
163- /// * `amount_sats` - The amount to send in satoshis
169+ /// * `amount_sats` - The amount to send in satoshis (or total balance for max send)
164170 /// * `fee_rate` - Optional fee rate to use (if None, will estimate based on current network conditions)
165171 /// * `utxos_to_spend` - Optional list of specific UTXOs to use for the transaction
166172 ///
@@ -176,6 +182,7 @@ impl OnchainPayment {
176182 /// * [`Error::WalletOperationFailed`] - If fee calculation fails
177183 ///
178184 /// [`send_to_address`]: Self::send_to_address
185+ /// [`BalanceDetails::total_onchain_balance_sats`]: crate::balance::BalanceDetails::total_onchain_balance_sats
179186 pub fn calculate_total_fee (
180187 & self , address : & bitcoin:: Address , amount_sats : u64 , fee_rate : Option < FeeRate > ,
181188 utxos_to_spend : Option < Vec < SpendableUtxo > > ,
@@ -187,18 +194,43 @@ impl OnchainPayment {
187194
188195 let cur_anchor_reserve_sats =
189196 crate :: total_anchor_channels_reserve_sats ( & self . channel_manager , & self . config ) ;
190- let send_amount =
191- OnchainSendAmount :: ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats } ;
197+
198+ // Get current balances
199+ let ( _total_balance, spendable_balance) = self . wallet . get_balances ( cur_anchor_reserve_sats)
200+ . unwrap_or ( ( 0 , 0 ) ) ;
201+
202+ // First try with the exact amount
192203 let outpoints = utxos_to_spend. map ( |utxos| utxos. into_iter ( ) . map ( |u| u. outpoint ) . collect ( ) ) ;
193204 let fee_rate_opt = maybe_map_fee_rate_opt ! ( fee_rate) ;
194-
195- self . wallet . calculate_transaction_fee (
205+
206+ // Try calculating with exact amount first
207+ let send_amount = OnchainSendAmount :: ExactRetainingReserve { amount_sats, cur_anchor_reserve_sats } ;
208+ let result = self . wallet . calculate_transaction_fee (
196209 address,
197210 send_amount,
198211 fee_rate_opt,
199- outpoints,
212+ outpoints. clone ( ) ,
200213 & self . channel_manager ,
201- )
214+ ) ;
215+
216+ // If we get InsufficientFunds and the amount is within the spendable balance,
217+ // try calculating as if sending all available funds
218+ if matches ! ( result, Err ( Error :: InsufficientFunds ) ) && amount_sats <= spendable_balance {
219+ // Try with AllRetainingReserve to calculate the fee for sending all
220+ let all_retaining = OnchainSendAmount :: AllRetainingReserve { cur_anchor_reserve_sats } ;
221+ if let Ok ( fee) = self . wallet . calculate_transaction_fee (
222+ address,
223+ all_retaining,
224+ fee_rate_opt,
225+ outpoints. clone ( ) ,
226+ & self . channel_manager ,
227+ ) {
228+ // Return the fee for sending all available funds
229+ return Ok ( fee) ;
230+ }
231+ }
232+
233+ result
202234 }
203235
204236 /// Send an on-chain payment to the given address.
0 commit comments