commit 211118ae8113a26e2e966a0c108f5091647381b0
parent 4004b8085f6c9971c30a7981d791adc7ac8ea191
Author: ThomasV <thomasv@electrum.org>
Date: Sat, 6 Jun 2020 11:55:33 +0200
fix #6210: show_onchain/lightning_invoice dialogs
Diffstat:
3 files changed, 73 insertions(+), 51 deletions(-)
diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py
@@ -664,8 +664,9 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
child_tx = self.wallet.cpfp(tx, 0)
if child_tx:
menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp(tx, child_tx))
- if invoice_keys:
- menu.addAction(read_QIcon("seal"), _("View invoice"), lambda: [self.parent.show_invoice(key) for key in invoice_keys])
+ for key in invoice_keys:
+ invoice = self.parent.wallet.get_invoice(key)
+ menu.addAction(_("View invoice"), lambda: self.parent.show_onchain_invoice(invoice))
if tx_URL:
menu.addAction(_("View on block explorer"), lambda: webopen(tx_URL))
menu.exec_(self.viewport().mapToGlobal(position))
diff --git a/electrum/gui/qt/invoice_list.py b/electrum/gui/qt/invoice_list.py
@@ -99,16 +99,14 @@ class InvoiceList(MyTreeView):
self.std_model.clear()
self.update_headers(self.__class__.headers)
for idx, item in enumerate(self.parent.wallet.get_invoices()):
- if item.type == PR_TYPE_LN:
+ if item.is_lightning():
key = item.rhash
icon_name = 'lightning.png'
- elif item.type == PR_TYPE_ONCHAIN:
+ else:
key = item.id
icon_name = 'bitcoin.png'
if item.bip70:
icon_name = 'seal.png'
- else:
- raise Exception('Unsupported type')
status = self.parent.wallet.get_invoice_status(item)
status_str = item.get_status_str(status)
message = item.message
@@ -154,10 +152,15 @@ class InvoiceList(MyTreeView):
if not item or not item_col0:
return
key = item_col0.data(ROLE_REQUEST_ID)
+ invoice = self.parent.wallet.get_invoice(key)
menu = QMenu(self)
self.add_copy_menu(menu, idx)
- invoice = self.parent.wallet.get_invoice(key)
- menu.addAction(_("Details"), lambda: self.parent.show_invoice(key))
+ if invoice.is_lightning():
+ menu.addAction(_("Details"), lambda: self.parent.show_lightning_invoice(invoice))
+ else:
+ if len(invoice.outputs) == 1:
+ menu.addAction(_("Copy Address"), lambda: self.parent.do_copy(invoice.get_address(), title='Bitcoin Address'))
+ menu.addAction(_("Details"), lambda: self.parent.show_onchain_invoice(invoice))
status = wallet.get_invoice_status(invoice)
if status == PR_UNPAID:
menu.addAction(_("Pay"), lambda: self.parent.do_pay_invoice(invoice))
diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
@@ -63,7 +63,7 @@ from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
InvalidBitcoinURI, maybe_extract_bolt11_invoice, NotEnoughFunds,
NoDynamicFeeEstimates, MultipleSpendMaxTxOutputs)
from electrum.invoices import PR_TYPE_ONCHAIN, PR_TYPE_LN, PR_DEFAULT_EXPIRATION_WHEN_CREATING
-from electrum.invoices import PR_PAID, PR_FAILED, pr_expiration_values, LNInvoice
+from electrum.invoices import PR_PAID, PR_FAILED, pr_expiration_values, LNInvoice, OnchainInvoice
from electrum.transaction import (Transaction, PartialTxInput,
PartialTransaction, PartialTxOutput)
from electrum.address_synchronizer import AddTransactionException
@@ -75,6 +75,7 @@ from electrum.exchange_rate import FxThread
from electrum.simple_config import SimpleConfig
from electrum.logging import Logger
from electrum.lnutil import ln_dummy_address
+from electrum.lnaddr import lndecode, LnDecodeException
from .exception_window import Exception_Hook
from .amountedit import AmountEdit, BTCAmountEdit, FreezableLineEdit, FeerateEdit
@@ -1813,7 +1814,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
def parse_lightning_invoice(self, invoice):
"""Parse ln invoice, and prepare the send tab for it."""
- from electrum.lnaddr import lndecode, LnDecodeException
try:
lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
except Exception as e:
@@ -1969,54 +1969,72 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.contact_list.update()
self.update_completions()
- def show_invoice(self, key):
- invoice = self.wallet.get_invoice(key)
- if invoice is None:
- self.show_error('Cannot find payment request in wallet.')
- return
- bip70 = invoice.bip70
- if bip70:
- pr = paymentrequest.PaymentRequest(bytes.fromhex(bip70))
+ def show_onchain_invoice(self, invoice: OnchainInvoice):
+ amount_str = self.format_amount(invoice.amount) + ' ' + self.base_unit()
+ d = WindowModalDialog(self, _("Onchain Invoice"))
+ vbox = QVBoxLayout(d)
+ grid = QGridLayout()
+ grid.addWidget(QLabel(_("Amount") + ':'), 1, 0)
+ grid.addWidget(QLabel(amount_str), 1, 1)
+ if len(invoice.outputs) == 1:
+ grid.addWidget(QLabel(_("Address") + ':'), 2, 0)
+ grid.addWidget(QLabel(invoice.get_address()), 2, 1)
+ else:
+ outputs_str = '\n'.join(map(lambda x: x.address + ' : ' + self.format_amount(x.value)+ self.base_unit(), invoice.outputs))
+ grid.addWidget(QLabel(_("Outputs") + ':'), 2, 0)
+ grid.addWidget(QLabel(outputs_str), 2, 1)
+ grid.addWidget(QLabel(_("Description") + ':'), 3, 0)
+ grid.addWidget(QLabel(invoice.message), 3, 1)
+ if invoice.exp:
+ grid.addWidget(QLabel(_("Expires") + ':'), 4, 0)
+ grid.addWidget(QLabel(format_time(invoice.exp + invoice.time)), 4, 1)
+ if invoice.bip70:
+ pr = paymentrequest.PaymentRequest(bytes.fromhex(invoice.bip70))
pr.verify(self.contacts)
- self.show_bip70_details(pr)
+ grid.addWidget(QLabel(_("Requestor") + ':'), 5, 0)
+ grid.addWidget(QLabel(pr.get_requestor()), 5, 1)
+ grid.addWidget(QLabel(_("Signature") + ':'), 6, 0)
+ grid.addWidget(QLabel(pr.get_verify_status()), 6, 1)
+ def do_export():
+ key = pr.get_id()
+ name = str(key) + '.bip70'
+ fn = self.getSaveFileName(_("Save invoice to file"), name, filter="*.bip70")
+ if not fn:
+ return
+ with open(fn, 'wb') as f:
+ data = f.write(pr.raw)
+ self.show_message(_('BIP70 invoice saved as' + ' ' + fn))
+ exportButton = EnterButton(_('Export'), do_export)
+ buttons = Buttons(exportButton, CloseButton(d))
+ else:
+ buttons = Buttons(CloseButton(d))
+ vbox.addLayout(grid)
+ vbox.addLayout(buttons)
+ d.exec_()
- def show_bip70_details(self, pr: 'paymentrequest.PaymentRequest'):
- key = pr.get_id()
- d = WindowModalDialog(self, _("BIP70 Invoice"))
+ def show_lightning_invoice(self, invoice: LNInvoice):
+ lnaddr = lndecode(invoice.invoice, expected_hrp=constants.net.SEGWIT_HRP)
+ d = WindowModalDialog(self, _("Lightning Invoice"))
vbox = QVBoxLayout(d)
grid = QGridLayout()
- grid.addWidget(QLabel(_("Requestor") + ':'), 0, 0)
- grid.addWidget(QLabel(pr.get_requestor()), 0, 1)
+ grid.addWidget(QLabel(_("Node ID") + ':'), 0, 0)
+ grid.addWidget(QLabel(lnaddr.pubkey.serialize().hex()), 0, 1)
grid.addWidget(QLabel(_("Amount") + ':'), 1, 0)
- outputs_str = '\n'.join(map(lambda x: self.format_amount(x.value)+ self.base_unit() + ' @ ' + x.address, pr.get_outputs()))
- grid.addWidget(QLabel(outputs_str), 1, 1)
- expires = pr.get_expiration_date()
- grid.addWidget(QLabel(_("Memo") + ':'), 2, 0)
- grid.addWidget(QLabel(pr.get_memo()), 2, 1)
- grid.addWidget(QLabel(_("Signature") + ':'), 3, 0)
- grid.addWidget(QLabel(pr.get_verify_status()), 3, 1)
- if expires:
+ amount_str = self.format_amount(invoice.amount) + ' ' + self.base_unit()
+ grid.addWidget(QLabel(amount_str), 1, 1)
+ grid.addWidget(QLabel(_("Description") + ':'), 2, 0)
+ grid.addWidget(QLabel(invoice.message), 2, 1)
+ grid.addWidget(QLabel(_("Hash") + ':'), 3, 0)
+ grid.addWidget(QLabel(lnaddr.paymenthash.hex()), 3, 1)
+ if invoice.exp:
grid.addWidget(QLabel(_("Expires") + ':'), 4, 0)
- grid.addWidget(QLabel(format_time(expires)), 4, 1)
+ grid.addWidget(QLabel(format_time(invoice.time + invoice.exp)), 4, 1)
vbox.addLayout(grid)
- def do_export():
- name = str(key) + '.bip70'
- fn = self.getSaveFileName(_("Save invoice to file"), name, filter="*.bip70")
- if not fn:
- return
- with open(fn, 'wb') as f:
- data = f.write(pr.raw)
- self.show_message(_('Invoice saved as' + ' ' + fn))
- exportButton = EnterButton(_('Save'), do_export)
- # note: "delete" disabled as invoice is saved with a different key in wallet.invoices that we do not have here
- # def do_delete():
- # if self.question(_('Delete invoice?')):
- # self.wallet.delete_invoice(key)
- # self.history_list.update()
- # self.invoice_list.update()
- # d.close()
- # deleteButton = EnterButton(_('Delete'), do_delete)
- vbox.addLayout(Buttons(exportButton, CloseButton(d)))
+ invoice_e = ShowQRTextEdit()
+ invoice_e.addCopyButton(self.app)
+ invoice_e.setText(invoice.invoice)
+ vbox.addWidget(invoice_e)
+ vbox.addLayout(Buttons(CloseButton(d),))
d.exec_()
def create_console_tab(self):