Browse Source

fix #6210: show_onchain/lightning_invoice dialogs

bip39-recovery
ThomasV 5 years ago
parent
commit
211118ae81
  1. 5
      electrum/gui/qt/history_list.py
  2. 15
      electrum/gui/qt/invoice_list.py
  3. 104
      electrum/gui/qt/main_window.py

5
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))

15
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))

104
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):

Loading…
Cancel
Save