tfix #6210: show_onchain/lightning_invoice dialogs - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 211118ae8113a26e2e966a0c108f5091647381b0 DIR parent 4004b8085f6c9971c30a7981d791adc7ac8ea191 HTML Author: ThomasV <thomasv@electrum.org> Date: Sat, 6 Jun 2020 11:55:33 +0200 fix #6210: show_onchain/lightning_invoice dialogs Diffstat: M electrum/gui/qt/history_list.py | 5 +++-- M electrum/gui/qt/invoice_list.py | 15 +++++++++------ M electrum/gui/qt/main_window.py | 104 ++++++++++++++++++------------- 3 files changed, 73 insertions(+), 51 deletions(-) --- DIR diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py t@@ -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)) DIR diff --git a/electrum/gui/qt/invoice_list.py b/electrum/gui/qt/invoice_list.py t@@ -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 t@@ -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)) DIR diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py t@@ -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 t@@ -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 t@@ -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: t@@ -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):