Browse Source

qml: add support for ln address and openalias, fix lnurl finalize step,

avoid overloading invoiceParser with new payment identifiers while potentially long-running
resolve/finalize steps are ongoing, show errors inresolve/finalize steps to user.
master
Sander van Grieken 2 years ago committed by accumulator
parent
commit
03dd38bfb8
  1. 2
      electrum/gui/qml/components/WalletMainView.qml
  2. 58
      electrum/gui/qml/qeinvoice.py

2
electrum/gui/qml/components/WalletMainView.qml

@ -309,6 +309,7 @@ Item {
Layout.preferredWidth: 1 Layout.preferredWidth: 1
icon.source: '../../icons/tab_send.png' icon.source: '../../icons/tab_send.png'
text: qsTr('Send') text: qsTr('Send')
enabled: !invoiceParser.busy
onClicked: openSendDialog() onClicked: openSendDialog()
onPressAndHold: { onPressAndHold: {
Config.userKnowsPressAndHold = true Config.userKnowsPressAndHold = true
@ -329,6 +330,7 @@ Item {
wallet: Daemon.currentWallet wallet: Daemon.currentWallet
onValidationError: (code, message) => { onValidationError: (code, message) => {
var dialog = app.messageDialog.createObject(app, { var dialog = app.messageDialog.createObject(app, {
title: qsTr('Error'),
text: message text: message
}) })
dialog.closed.connect(function() { dialog.closed.connect(function() {

58
electrum/gui/qml/qeinvoice.py

@ -327,9 +327,9 @@ class QEInvoice(QObject, QtEventListener):
self.userinfo = { self.userinfo = {
PR_EXPIRED: _('This invoice has expired'), PR_EXPIRED: _('This invoice has expired'),
PR_PAID: _('This invoice was already paid'), PR_PAID: _('This invoice was already paid'),
PR_BROADCASTING: _('Payment in progress...') + ' (' + _('broadcasting') + ')', PR_BROADCASTING: _('Payment in progress...') + ' (' + _('broadcasting') + ')',
PR_BROADCAST: _('Payment in progress...') + ' (' + _('broadcast successfully') + ')', PR_BROADCAST: _('Payment in progress...') + ' (' + _('broadcast successfully') + ')',
PR_UNCONFIRMED: _('Payment in progress...') + ' (' + _('waiting for confirmation') + ')', PR_UNCONFIRMED: _('Payment in progress...') + ' (' + _('waiting for confirmation') + ')',
PR_UNKNOWN: _('Invoice has unknown status'), PR_UNKNOWN: _('Invoice has unknown status'),
}[self.status] }[self.status]
@ -395,13 +395,15 @@ class QEInvoiceParser(QEInvoice):
_logger = get_logger(__name__) _logger = get_logger(__name__)
validationSuccess = pyqtSignal() validationSuccess = pyqtSignal()
validationWarning = pyqtSignal([str,str], arguments=['code', 'message']) validationWarning = pyqtSignal([str, str], arguments=['code', 'message'])
validationError = pyqtSignal([str,str], arguments=['code', 'message']) validationError = pyqtSignal([str, str], arguments=['code', 'message'])
invoiceCreateError = pyqtSignal([str,str], arguments=['code', 'message']) invoiceCreateError = pyqtSignal([str, str], arguments=['code', 'message'])
lnurlRetrieved = pyqtSignal() lnurlRetrieved = pyqtSignal()
lnurlError = pyqtSignal([str,str], arguments=['code', 'message']) lnurlError = pyqtSignal([str, str], arguments=['code', 'message'])
busyChanged = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
@ -409,6 +411,7 @@ class QEInvoiceParser(QEInvoice):
self._recipient = '' self._recipient = ''
self._pi = None self._pi = None
self._lnurlData = None self._lnurlData = None
self._busy = False
self.clear() self.clear()
@ -434,6 +437,10 @@ class QEInvoiceParser(QEInvoice):
def isLnurlPay(self): def isLnurlPay(self):
return self._lnurlData is not None return self._lnurlData is not None
@pyqtProperty(bool, notify=busyChanged)
def busy(self):
return self._busy
@pyqtSlot() @pyqtSlot()
def clear(self): def clear(self):
self.recipient = '' self.recipient = ''
@ -492,7 +499,9 @@ class QEInvoiceParser(QEInvoice):
self._pi = PaymentIdentifier(self._wallet.wallet, recipient) self._pi = PaymentIdentifier(self._wallet.wallet, recipient)
if not self._pi.is_valid() or self._pi.type not in [PaymentIdentifierType.SPK, PaymentIdentifierType.BIP21, if not self._pi.is_valid() or self._pi.type not in [PaymentIdentifierType.SPK, PaymentIdentifierType.BIP21,
PaymentIdentifierType.BIP70, PaymentIdentifierType.BOLT11, PaymentIdentifierType.BIP70, PaymentIdentifierType.BOLT11,
PaymentIdentifierType.LNURLP]: PaymentIdentifierType.LNURLP,
PaymentIdentifierType.EMAILLIKE,
PaymentIdentifierType.DOMAINLIKE]:
self.validationError.emit('unknown', _('Unknown invoice')) self.validationError.emit('unknown', _('Unknown invoice'))
return return
@ -509,7 +518,7 @@ class QEInvoiceParser(QEInvoice):
self.resolve_pi() self.resolve_pi()
return return
if self._pi.type == PaymentIdentifierType.LNURLP: if self._pi.type in [PaymentIdentifierType.LNURLP, PaymentIdentifierType.LNADDR]:
self.on_lnurl(self._pi.lnurl_data) self.on_lnurl(self._pi.lnurl_data)
return return
@ -518,7 +527,7 @@ class QEInvoiceParser(QEInvoice):
return return
if self._pi.is_available(): if self._pi.is_available():
if self._pi.type == PaymentIdentifierType.SPK: if self._pi.type in [PaymentIdentifierType.SPK, PaymentIdentifierType.OPENALIAS]:
outputs = [PartialTxOutput(scriptpubkey=self._pi.spk, value=0)] outputs = [PartialTxOutput(scriptpubkey=self._pi.spk, value=0)]
invoice = self.create_onchain_invoice(outputs, None, None, None) invoice = self.create_onchain_invoice(outputs, None, None, None)
self._logger.debug(repr(invoice)) self._logger.debug(repr(invoice))
@ -563,11 +572,25 @@ class QEInvoiceParser(QEInvoice):
assert self._pi.need_resolve() assert self._pi.need_resolve()
def on_finished(pi): def on_finished(pi):
self._busy = False
self.busyChanged.emit()
if pi.is_error(): if pi.is_error():
pass if pi.type in [PaymentIdentifierType.EMAILLIKE, PaymentIdentifierType.DOMAINLIKE]:
msg = _('Could not resolve address')
elif pi.type == PaymentIdentifierType.LNURLP:
msg = _('Could not resolve LNURL')
elif pi.type == PaymentIdentifierType.BIP70:
msg = _('Could not resolve BIP70 payment request: {}').format(pi.error)
else:
msg = _('Could not resolve')
self.validationError.emit('resolve', msg)
else: else:
self._update_from_payment_identifier() self._update_from_payment_identifier()
self._busy = True
self.busyChanged.emit()
self._pi.resolve(on_finished=on_finished) self._pi.resolve(on_finished=on_finished)
def on_lnurl(self, lnurldata): def on_lnurl(self, lnurldata):
@ -576,7 +599,7 @@ class QEInvoiceParser(QEInvoice):
self._lnurlData = { self._lnurlData = {
'domain': urlparse(lnurldata.callback_url).netloc, 'domain': urlparse(lnurldata.callback_url).netloc,
'callback_url' : lnurldata.callback_url, 'callback_url': lnurldata.callback_url,
'min_sendable_sat': lnurldata.min_sendable_sat, 'min_sendable_sat': lnurldata.min_sendable_sat,
'max_sendable_sat': lnurldata.max_sendable_sat, 'max_sendable_sat': lnurldata.max_sendable_sat,
'metadata_plaintext': lnurldata.metadata_plaintext, 'metadata_plaintext': lnurldata.metadata_plaintext,
@ -598,6 +621,9 @@ class QEInvoiceParser(QEInvoice):
comment = None comment = None
def on_finished(pi): def on_finished(pi):
self._busy = False
self.busyChanged.emit()
if pi.is_error(): if pi.is_error():
if pi.state == PaymentIdentifierState.INVALID_AMOUNT: if pi.state == PaymentIdentifierState.INVALID_AMOUNT:
self.lnurlError.emit('amount', pi.get_error()) self.lnurlError.emit('amount', pi.get_error())
@ -606,6 +632,9 @@ class QEInvoiceParser(QEInvoice):
else: else:
self.on_lnurl_invoice(self.amountOverride.satsInt, pi.bolt11) self.on_lnurl_invoice(self.amountOverride.satsInt, pi.bolt11)
self._busy = True
self.busyChanged.emit()
self._pi.finalize(amount_sat=amount, comment=comment, on_finished=on_finished) self._pi.finalize(amount_sat=amount, comment=comment, on_finished=on_finished)
def on_lnurl_invoice(self, orig_amount, invoice): def on_lnurl_invoice(self, orig_amount, invoice):
@ -613,11 +642,10 @@ class QEInvoiceParser(QEInvoice):
self._logger.debug(f'{repr(invoice)}') self._logger.debug(f'{repr(invoice)}')
# assure no shenanigans with the bolt11 invoice we get back # assure no shenanigans with the bolt11 invoice we get back
lninvoice = Invoice.from_bech32(invoice) if orig_amount * 1000 != invoice.amount_msat: # TODO msat precision can cause trouble here
if orig_amount * 1000 != lninvoice.amount_msat: # TODO msat precision can cause trouble here
raise Exception('Unexpected amount in invoice, differs from lnurl-pay specified amount') raise Exception('Unexpected amount in invoice, differs from lnurl-pay specified amount')
self.recipient = invoice self.recipient = invoice.lightning_invoice
@pyqtSlot() @pyqtSlot()
def saveInvoice(self): def saveInvoice(self):

Loading…
Cancel
Save