From 42f2a3da317471748848d04cc6d3b136b71103f4 Mon Sep 17 00:00:00 2001
From: SomberNight <somber.night@protonmail.com>
Date: Tue, 30 Aug 2022 11:46:52 +0000
Subject: [PATCH] Qt pay_lightning_invoice: handle NoDynamicFeeEstimates

`wallet.make_unsigned_transaction` can raise NotEnoughFunds or NoDynamicFeeEstimates.
These are "expected" exceptions that need to be handled or worked around. Added a note
of this in the docstring now.

We now handle NoDynamicFeeEstimates by allowing a static fallback fee in
`wallet.can_pay_onchain` and `lnworker.suggest_funding_amount`. It should be
fine to have a static fallback in these cases, as the user still has a chance
to set their own fee later in the flow.
(though ofc the static fallback might be too high in some mempool conditions,
in which case e.g. can_pay_onchain might return a false-negative, but this
is still an improvement over raising I believe)

fixes https://github.com/spesmilo/electrum/issues/5784
---
 electrum/gui/qt/send_tab.py | 2 +-
 electrum/lnworker.py        | 5 +++--
 electrum/wallet.py          | 4 +++-
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/electrum/gui/qt/send_tab.py b/electrum/gui/qt/send_tab.py
index a3fe4966a..395cba612 100644
--- a/electrum/gui/qt/send_tab.py
+++ b/electrum/gui/qt/send_tab.py
@@ -686,7 +686,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
                 choices[3] = msg
             msg = _('You cannot pay that invoice using Lightning.')
             if self.wallet.lnworker.channels:
-                msg += '\n' + _('Your channels can send {}.').format(self.format_amount(num_sats_can_send) + self.base_unit())
+                msg += '\n' + _('Your channels can send {}.').format(self.format_amount(num_sats_can_send) + ' ' + self.base_unit())
             if not choices:
                 self.window.show_error(msg)
                 return
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
index 07bf038f2..20a67e5da 100644
--- a/electrum/lnworker.py
+++ b/electrum/lnworker.py
@@ -1097,15 +1097,16 @@ class LNWallet(LNWorker):
         min_funding_sat = max(min_funding_sat, 100_000) # at least 1mBTC
         if min_funding_sat > LN_MAX_FUNDING_SAT:
             return
+        fee_est = partial(self.config.estimate_fee, allow_fallback_to_static_rates=True)  # to avoid NoDynamicFeeEstimates
         try:
-            self.mktx_for_open_channel(coins=coins, funding_sat=min_funding_sat, node_id=bytes(32), fee_est=None)
+            self.mktx_for_open_channel(coins=coins, funding_sat=min_funding_sat, node_id=bytes(32), fee_est=fee_est)
             funding_sat = min_funding_sat
         except NotEnoughFunds:
             return
         # if available, suggest twice that amount:
         if 2 * min_funding_sat <= LN_MAX_FUNDING_SAT:
             try:
-                self.mktx_for_open_channel(coins=coins, funding_sat=2*min_funding_sat, node_id=bytes(32), fee_est=None)
+                self.mktx_for_open_channel(coins=coins, funding_sat=2*min_funding_sat, node_id=bytes(32), fee_est=fee_est)
                 funding_sat = 2 * min_funding_sat
             except NotEnoughFunds:
                 pass
diff --git a/electrum/wallet.py b/electrum/wallet.py
index f8c4f1440..b70685b0d 100644
--- a/electrum/wallet.py
+++ b/electrum/wallet.py
@@ -1548,11 +1548,12 @@ class Abstract_Wallet(ABC, Logger, EventListener):
         return selected_addr
 
     def can_pay_onchain(self, outputs, coins=None):
+        fee = partial(self.config.estimate_fee, allow_fallback_to_static_rates=True)  # to avoid NoDynamicFeeEstimates
         try:
             self.make_unsigned_transaction(
                 coins=coins,
                 outputs=outputs,
-                fee=None)
+                fee=fee)
         except NotEnoughFunds:
             return False
         return True
@@ -1565,6 +1566,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
             change_addr: str = None,
             is_sweep=False,
             rbf=False) -> PartialTransaction:
+        """Can raise NotEnoughFunds or NoDynamicFeeEstimates."""
 
         if not coins:  # any bitcoin tx must have at least 1 input by consensus
             raise NotEnoughFunds()