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.
This commit is contained in:
committed by
accumulator
parent
ff77013a82
commit
03dd38bfb8
@@ -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() {
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user