Browse Source

fix #6210: show_onchain/lightning_invoice dialogs

master
ThomasV 6 years ago
parent
commit
211118ae81
  1. 5
      electrum/gui/qt/history_list.py
  2. 15
      electrum/gui/qt/invoice_list.py
  3. 96
      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) child_tx = self.wallet.cpfp(tx, 0)
if child_tx: if child_tx:
menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp(tx, child_tx)) menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp(tx, child_tx))
if invoice_keys: for key in invoice_keys:
menu.addAction(read_QIcon("seal"), _("View invoice"), lambda: [self.parent.show_invoice(key) 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: if tx_URL:
menu.addAction(_("View on block explorer"), lambda: webopen(tx_URL)) menu.addAction(_("View on block explorer"), lambda: webopen(tx_URL))
menu.exec_(self.viewport().mapToGlobal(position)) 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.std_model.clear()
self.update_headers(self.__class__.headers) self.update_headers(self.__class__.headers)
for idx, item in enumerate(self.parent.wallet.get_invoices()): for idx, item in enumerate(self.parent.wallet.get_invoices()):
if item.type == PR_TYPE_LN: if item.is_lightning():
key = item.rhash key = item.rhash
icon_name = 'lightning.png' icon_name = 'lightning.png'
elif item.type == PR_TYPE_ONCHAIN: else:
key = item.id key = item.id
icon_name = 'bitcoin.png' icon_name = 'bitcoin.png'
if item.bip70: if item.bip70:
icon_name = 'seal.png' icon_name = 'seal.png'
else:
raise Exception('Unsupported type')
status = self.parent.wallet.get_invoice_status(item) status = self.parent.wallet.get_invoice_status(item)
status_str = item.get_status_str(status) status_str = item.get_status_str(status)
message = item.message message = item.message
@ -154,10 +152,15 @@ class InvoiceList(MyTreeView):
if not item or not item_col0: if not item or not item_col0:
return return
key = item_col0.data(ROLE_REQUEST_ID) key = item_col0.data(ROLE_REQUEST_ID)
invoice = self.parent.wallet.get_invoice(key)
menu = QMenu(self) menu = QMenu(self)
self.add_copy_menu(menu, idx) self.add_copy_menu(menu, idx)
invoice = self.parent.wallet.get_invoice(key) if invoice.is_lightning():
menu.addAction(_("Details"), lambda: self.parent.show_invoice(key)) 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) status = wallet.get_invoice_status(invoice)
if status == PR_UNPAID: if status == PR_UNPAID:
menu.addAction(_("Pay"), lambda: self.parent.do_pay_invoice(invoice)) menu.addAction(_("Pay"), lambda: self.parent.do_pay_invoice(invoice))

96
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, InvalidBitcoinURI, maybe_extract_bolt11_invoice, NotEnoughFunds,
NoDynamicFeeEstimates, MultipleSpendMaxTxOutputs) NoDynamicFeeEstimates, MultipleSpendMaxTxOutputs)
from electrum.invoices import PR_TYPE_ONCHAIN, PR_TYPE_LN, PR_DEFAULT_EXPIRATION_WHEN_CREATING 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, from electrum.transaction import (Transaction, PartialTxInput,
PartialTransaction, PartialTxOutput) PartialTransaction, PartialTxOutput)
from electrum.address_synchronizer import AddTransactionException from electrum.address_synchronizer import AddTransactionException
@ -75,6 +75,7 @@ from electrum.exchange_rate import FxThread
from electrum.simple_config import SimpleConfig from electrum.simple_config import SimpleConfig
from electrum.logging import Logger from electrum.logging import Logger
from electrum.lnutil import ln_dummy_address from electrum.lnutil import ln_dummy_address
from electrum.lnaddr import lndecode, LnDecodeException
from .exception_window import Exception_Hook from .exception_window import Exception_Hook
from .amountedit import AmountEdit, BTCAmountEdit, FreezableLineEdit, FeerateEdit from .amountedit import AmountEdit, BTCAmountEdit, FreezableLineEdit, FeerateEdit
@ -1813,7 +1814,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
def parse_lightning_invoice(self, invoice): def parse_lightning_invoice(self, invoice):
"""Parse ln invoice, and prepare the send tab for it.""" """Parse ln invoice, and prepare the send tab for it."""
from electrum.lnaddr import lndecode, LnDecodeException
try: try:
lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP) lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
except Exception as e: except Exception as e:
@ -1969,54 +1969,72 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.contact_list.update() self.contact_list.update()
self.update_completions() self.update_completions()
def show_invoice(self, key): def show_onchain_invoice(self, invoice: OnchainInvoice):
invoice = self.wallet.get_invoice(key) amount_str = self.format_amount(invoice.amount) + ' ' + self.base_unit()
if invoice is None: d = WindowModalDialog(self, _("Onchain Invoice"))
self.show_error('Cannot find payment request in wallet.')
return
bip70 = invoice.bip70
if bip70:
pr = paymentrequest.PaymentRequest(bytes.fromhex(bip70))
pr.verify(self.contacts)
self.show_bip70_details(pr)
def show_bip70_details(self, pr: 'paymentrequest.PaymentRequest'):
key = pr.get_id()
d = WindowModalDialog(self, _("BIP70 Invoice"))
vbox = QVBoxLayout(d) vbox = QVBoxLayout(d)
grid = QGridLayout() grid = QGridLayout()
grid.addWidget(QLabel(_("Requestor") + ':'), 0, 0)
grid.addWidget(QLabel(pr.get_requestor()), 0, 1)
grid.addWidget(QLabel(_("Amount") + ':'), 1, 0) 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(amount_str), 1, 1)
grid.addWidget(QLabel(outputs_str), 1, 1) if len(invoice.outputs) == 1:
expires = pr.get_expiration_date() grid.addWidget(QLabel(_("Address") + ':'), 2, 0)
grid.addWidget(QLabel(_("Memo") + ':'), 2, 0) grid.addWidget(QLabel(invoice.get_address()), 2, 1)
grid.addWidget(QLabel(pr.get_memo()), 2, 1) else:
grid.addWidget(QLabel(_("Signature") + ':'), 3, 0) outputs_str = '\n'.join(map(lambda x: x.address + ' : ' + self.format_amount(x.value)+ self.base_unit(), invoice.outputs))
grid.addWidget(QLabel(pr.get_verify_status()), 3, 1) grid.addWidget(QLabel(_("Outputs") + ':'), 2, 0)
if expires: 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(_("Expires") + ':'), 4, 0)
grid.addWidget(QLabel(format_time(expires)), 4, 1) grid.addWidget(QLabel(format_time(invoice.exp + invoice.time)), 4, 1)
vbox.addLayout(grid) if invoice.bip70:
pr = paymentrequest.PaymentRequest(bytes.fromhex(invoice.bip70))
pr.verify(self.contacts)
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(): def do_export():
key = pr.get_id()
name = str(key) + '.bip70' name = str(key) + '.bip70'
fn = self.getSaveFileName(_("Save invoice to file"), name, filter="*.bip70") fn = self.getSaveFileName(_("Save invoice to file"), name, filter="*.bip70")
if not fn: if not fn:
return return
with open(fn, 'wb') as f: with open(fn, 'wb') as f:
data = f.write(pr.raw) data = f.write(pr.raw)
self.show_message(_('Invoice saved as' + ' ' + fn)) self.show_message(_('BIP70 invoice saved as' + ' ' + fn))
exportButton = EnterButton(_('Save'), do_export) exportButton = EnterButton(_('Export'), do_export)
# note: "delete" disabled as invoice is saved with a different key in wallet.invoices that we do not have here buttons = Buttons(exportButton, CloseButton(d))
# def do_delete(): else:
# if self.question(_('Delete invoice?')): buttons = Buttons(CloseButton(d))
# self.wallet.delete_invoice(key) vbox.addLayout(grid)
# self.history_list.update() vbox.addLayout(buttons)
# self.invoice_list.update() d.exec_()
# d.close()
# deleteButton = EnterButton(_('Delete'), do_delete) def show_lightning_invoice(self, invoice: LNInvoice):
vbox.addLayout(Buttons(exportButton, CloseButton(d))) lnaddr = lndecode(invoice.invoice, expected_hrp=constants.net.SEGWIT_HRP)
d = WindowModalDialog(self, _("Lightning Invoice"))
vbox = QVBoxLayout(d)
grid = QGridLayout()
grid.addWidget(QLabel(_("Node ID") + ':'), 0, 0)
grid.addWidget(QLabel(lnaddr.pubkey.serialize().hex()), 0, 1)
grid.addWidget(QLabel(_("Amount") + ':'), 1, 0)
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(invoice.time + invoice.exp)), 4, 1)
vbox.addLayout(grid)
invoice_e = ShowQRTextEdit()
invoice_e.addCopyButton(self.app)
invoice_e.setText(invoice.invoice)
vbox.addWidget(invoice_e)
vbox.addLayout(Buttons(CloseButton(d),))
d.exec_() d.exec_()
def create_console_tab(self): def create_console_tab(self):

Loading…
Cancel
Save