qt send: use bolt11 fallback addr even if LN is disabled
Given a wallet with LN disabled, and a bolt11 invoice (or a bip21 uri that only contains bolt11 but lacks a top-level address), if the bolt11 invoice includes a fallback address, we would previously just error "Lightning is disabled". Now we offer the user to pay on-chain using the fallback address. closes https://github.com/spesmilo/electrum/issues/8047
This commit is contained in:
@@ -483,7 +483,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
self.amount_e.textEdited.emit("")
|
self.amount_e.textEdited.emit("")
|
||||||
self.window.show_send_tab()
|
self.window.show_send_tab()
|
||||||
|
|
||||||
def read_invoice(self):
|
def read_invoice(self) -> Optional[Invoice]:
|
||||||
if self.check_send_tab_payto_line_and_show_errors():
|
if self.check_send_tab_payto_line_and_show_errors():
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
@@ -491,9 +491,6 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
invoice_str = self.payto_e.lightning_invoice
|
invoice_str = self.payto_e.lightning_invoice
|
||||||
if not invoice_str:
|
if not invoice_str:
|
||||||
return
|
return
|
||||||
if not self.wallet.has_lightning():
|
|
||||||
self.show_error(_('Lightning is disabled'))
|
|
||||||
return
|
|
||||||
invoice = Invoice.from_bech32(invoice_str)
|
invoice = Invoice.from_bech32(invoice_str)
|
||||||
if invoice.amount_msat is None:
|
if invoice.amount_msat is None:
|
||||||
amount_sat = self.amount_e.get_amount()
|
amount_sat = self.amount_e.get_amount()
|
||||||
@@ -502,6 +499,9 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
else:
|
else:
|
||||||
self.show_error(_('No amount'))
|
self.show_error(_('No amount'))
|
||||||
return
|
return
|
||||||
|
if not self.wallet.has_lightning() and not invoice.can_be_paid_onchain():
|
||||||
|
self.show_error(_('Lightning is disabled'))
|
||||||
|
return
|
||||||
return invoice
|
return invoice
|
||||||
else:
|
else:
|
||||||
outputs = self.read_outputs()
|
outputs = self.read_outputs()
|
||||||
@@ -646,19 +646,22 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
|
|
||||||
def pay_lightning_invoice(self, invoice: Invoice):
|
def pay_lightning_invoice(self, invoice: Invoice):
|
||||||
amount_sat = invoice.get_amount_sat()
|
amount_sat = invoice.get_amount_sat()
|
||||||
key = invoice.get_id()
|
|
||||||
if amount_sat is None:
|
if amount_sat is None:
|
||||||
raise Exception("missing amount for LN invoice")
|
raise Exception("missing amount for LN invoice")
|
||||||
if not self.wallet.lnworker.can_pay_invoice(invoice):
|
# note: lnworker might be None if LN is disabled,
|
||||||
num_sats_can_send = int(self.wallet.lnworker.num_sats_can_send())
|
# in which case we should still offer the user to pay onchain.
|
||||||
lightning_needed = amount_sat - num_sats_can_send
|
lnworker = self.wallet.lnworker
|
||||||
lightning_needed += (lightning_needed // 20) # operational safety margin
|
if lnworker is None or not lnworker.can_pay_invoice(invoice):
|
||||||
coins = self.window.get_coins(nonlocal_only=True)
|
coins = self.window.get_coins(nonlocal_only=True)
|
||||||
can_pay_onchain = invoice.get_address() and self.wallet.can_pay_onchain(invoice.get_outputs(), coins=coins)
|
can_pay_onchain = invoice.can_be_paid_onchain() and self.wallet.can_pay_onchain(invoice.get_outputs(), coins=coins)
|
||||||
can_pay_with_new_channel = self.wallet.lnworker.suggest_funding_amount(amount_sat, coins=coins)
|
can_pay_with_new_channel = False
|
||||||
can_pay_with_swap = self.wallet.lnworker.suggest_swap_to_send(amount_sat, coins=coins)
|
can_pay_with_swap = False
|
||||||
rebalance_suggestion = self.wallet.lnworker.suggest_rebalance_to_send(amount_sat)
|
can_rebalance = False
|
||||||
can_rebalance = bool(rebalance_suggestion) and self.window.num_tasks() == 0
|
if lnworker:
|
||||||
|
can_pay_with_new_channel = lnworker.suggest_funding_amount(amount_sat, coins=coins)
|
||||||
|
can_pay_with_swap = lnworker.suggest_swap_to_send(amount_sat, coins=coins)
|
||||||
|
rebalance_suggestion = lnworker.suggest_rebalance_to_send(amount_sat)
|
||||||
|
can_rebalance = bool(rebalance_suggestion) and self.window.num_tasks() == 0
|
||||||
choices = {}
|
choices = {}
|
||||||
if can_rebalance:
|
if can_rebalance:
|
||||||
msg = ''.join([
|
msg = ''.join([
|
||||||
@@ -685,7 +688,8 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
])
|
])
|
||||||
choices[3] = msg
|
choices[3] = msg
|
||||||
msg = _('You cannot pay that invoice using Lightning.')
|
msg = _('You cannot pay that invoice using Lightning.')
|
||||||
if self.wallet.lnworker.channels:
|
if lnworker and lnworker.channels:
|
||||||
|
num_sats_can_send = int(lnworker.num_sats_can_send())
|
||||||
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:
|
if not choices:
|
||||||
self.window.show_error(msg)
|
self.window.show_error(msg)
|
||||||
@@ -706,13 +710,14 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
self.pay_onchain_dialog(coins, invoice.get_outputs())
|
self.pay_onchain_dialog(coins, invoice.get_outputs())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
assert lnworker is not None
|
||||||
# FIXME this is currently lying to user as we truncate to satoshis
|
# FIXME this is currently lying to user as we truncate to satoshis
|
||||||
amount_msat = invoice.get_amount_msat()
|
amount_msat = invoice.get_amount_msat()
|
||||||
msg = _("Pay lightning invoice?") + '\n\n' + _("This will send {}?").format(self.format_amount_and_units(Decimal(amount_msat)/1000))
|
msg = _("Pay lightning invoice?") + '\n\n' + _("This will send {}?").format(self.format_amount_and_units(Decimal(amount_msat)/1000))
|
||||||
if not self.question(msg):
|
if not self.question(msg):
|
||||||
return
|
return
|
||||||
self.save_pending_invoice()
|
self.save_pending_invoice()
|
||||||
coro = self.wallet.lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat)
|
coro = lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat)
|
||||||
self.window.run_coroutine_from_thread(coro, _('Sending payment'))
|
self.window.run_coroutine_from_thread(coro, _('Sending payment'))
|
||||||
|
|
||||||
def broadcast_transaction(self, tx: Transaction):
|
def broadcast_transaction(self, tx: Transaction):
|
||||||
|
|||||||
@@ -136,6 +136,12 @@ class Invoice(StoredObject):
|
|||||||
outputs = self.outputs
|
outputs = self.outputs
|
||||||
return outputs
|
return outputs
|
||||||
|
|
||||||
|
def can_be_paid_onchain(self) -> bool:
|
||||||
|
if self.is_lightning():
|
||||||
|
return bool(self._lnaddr.get_fallback_address())
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
def get_expiration_date(self):
|
def get_expiration_date(self):
|
||||||
# 0 means never
|
# 0 means never
|
||||||
return self.exp + self.time if self.exp else 0
|
return self.exp + self.time if self.exp else 0
|
||||||
|
|||||||
Reference in New Issue
Block a user