qml: Handle situation where no more addresses are available without
creating addresses beyond the gap limit. - if lightning is enabled, propose to create a lightning-only invoice - otherwise, propose to reuse an address - never generate addresses beyond the gap limit Implementation: - createDefaultRequest is removed - create_bitcoin_address is called whether the wallet has lightning or not
This commit is contained in:
@@ -356,12 +356,7 @@ ElDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (dialog.key) {
|
request.key = dialog.key
|
||||||
request.key = dialog.key
|
|
||||||
} else {
|
|
||||||
// callLater to make sure any popups are on top of the dialog stacking order
|
|
||||||
Qt.callLater(createDefaultRequest)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hack. delay qr rendering until dialog is shown
|
// hack. delay qr rendering until dialog is shown
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ Item {
|
|||||||
property var _sendDialog
|
property var _sendDialog
|
||||||
property string _intentUri
|
property string _intentUri
|
||||||
|
|
||||||
property bool _ignore_gaplimit: false
|
property string _request_amount
|
||||||
property bool _reuse_address: false
|
property string _request_description
|
||||||
|
property string _request_expiry
|
||||||
|
|
||||||
function openInvoice(key) {
|
function openInvoice(key) {
|
||||||
var dialog = invoiceDialog.createObject(app, { invoice: invoiceParser, invoice_key: key })
|
var dialog = invoiceDialog.createObject(app, { invoice: invoiceParser, invoice_key: key })
|
||||||
@@ -171,7 +172,7 @@ Item {
|
|||||||
icon.source: '../../icons/tab_receive.png'
|
icon.source: '../../icons/tab_receive.png'
|
||||||
text: qsTr('Receive')
|
text: qsTr('Receive')
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var dialog = receiveDetails.createObject(mainView)
|
var dialog = receiveDetailsDialog.createObject(mainView)
|
||||||
dialog.open()
|
dialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,20 +245,18 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: Daemon.currentWallet
|
target: Daemon.currentWallet
|
||||||
function onRequestCreateSuccess(key) {
|
function onRequestCreateSuccess(key) {
|
||||||
openRequest(key)
|
openRequest(key)
|
||||||
}
|
}
|
||||||
function onRequestCreateError(code, error) {
|
function onRequestCreateError(code, error) {
|
||||||
if (code == 'gaplimit') {
|
if (code == 'ln') {
|
||||||
var dialog = app.messageDialog.createObject(app, {text: error, yesno: true})
|
var dialog = app.messageDialog.createObject(app, {text: error, yesno: true})
|
||||||
dialog.yesClicked.connect(function() {
|
dialog.yesClicked.connect(function() {
|
||||||
_ignore_gaplimit = true
|
createRequest(true, false)
|
||||||
createDefaultRequest()
|
|
||||||
})
|
})
|
||||||
} else if (code == 'non-deterministic') {
|
} else if (code == 'reuse_addr') {
|
||||||
var dialog = app.messageDialog.createObject(app, {text: error, yesno: true})
|
var dialog = app.messageDialog.createObject(app, {text: error, yesno: true})
|
||||||
dialog.yesClicked.connect(function() {
|
dialog.yesClicked.connect(function() {
|
||||||
_reuse_address = true
|
createRequest(false, true)
|
||||||
createDefaultRequest()
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@@ -354,25 +353,30 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRequest(receiveDetailsDialog) {
|
function createRequest(lightning_only, reuse_address) {
|
||||||
var qamt = Config.unitsToSats(receiveDetailsDialog.amount)
|
var qamt = Config.unitsToSats(_request_amount)
|
||||||
Daemon.currentWallet.createRequest(qamt, receiveDetailsDialog.description, receiveDetailsDialog.expiry, _ignore_gaplimit, _reuse_address)
|
Daemon.currentWallet.createRequest(qamt, _request_description, _request_expiry, lightning_only, reuse_address)
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: receiveDetails
|
id: receiveDetailsDialog
|
||||||
|
|
||||||
ReceiveDetailsDialog {
|
ReceiveDetailsDialog {
|
||||||
id: receiveDetailsDialog
|
id: _receiveDetailsDialog
|
||||||
width: parent.width * 0.9
|
width: parent.width * 0.9
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
console.log('accepted')
|
console.log('accepted')
|
||||||
createRequest(receiveDetailsDialog)
|
_request_amount = _receiveDetailsDialog.amount
|
||||||
|
_request_description = _receiveDetailsDialog.description
|
||||||
|
_request_expiry = _receiveDetailsDialog.expiry
|
||||||
|
createRequest(false, false)
|
||||||
}
|
}
|
||||||
onRejected: {
|
onRejected: {
|
||||||
console.log('rejected')
|
console.log('rejected')
|
||||||
}
|
}
|
||||||
}
|
onClosed: destroy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
|||||||
@@ -577,39 +577,26 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
|
|
||||||
threading.Thread(target=pay_thread, daemon=True).start()
|
threading.Thread(target=pay_thread, daemon=True).start()
|
||||||
|
|
||||||
def create_bitcoin_request(self, amount: int, message: str, expiration: int, *, ignore_gap: bool = False, reuse_address: bool = False) -> Optional[Tuple]:
|
def create_bitcoin_request(self, amount: int, message: str, expiration: int, *, lightning_only: bool = False, reuse_address: bool = False) -> Optional[Tuple]:
|
||||||
addr = self.wallet.get_unused_address()
|
addr = self.wallet.get_unused_address()
|
||||||
if addr is None:
|
if addr is None:
|
||||||
if not self.wallet.is_deterministic(): # imported wallet
|
if reuse_address:
|
||||||
if not reuse_address:
|
|
||||||
msg = [
|
|
||||||
_('No more addresses in your wallet.'), ' ',
|
|
||||||
_('You are using a non-deterministic wallet, which cannot create new addresses.'), ' ',
|
|
||||||
_('If you want to create new addresses, use a deterministic wallet instead.'), '\n\n',
|
|
||||||
_('Creating a new payment request will reuse one of your addresses and overwrite an existing request. Continue anyway?'),
|
|
||||||
]
|
|
||||||
self.requestCreateError.emit('non-deterministic',''.join(msg))
|
|
||||||
return
|
|
||||||
addr = self.wallet.get_receiving_address()
|
addr = self.wallet.get_receiving_address()
|
||||||
else: # deterministic wallet
|
elif lightning_only:
|
||||||
if not ignore_gap:
|
addr = None
|
||||||
self.requestCreateError.emit('gaplimit',_("Warning: The next address will not be recovered automatically if you restore your wallet from seed; you may need to add it manually.\n\nThis occurs because you have too many unused addresses in your wallet. To avoid this situation, use the existing addresses first.\n\nCreate anyway?"))
|
else:
|
||||||
return
|
has_lightning = self.wallet.has_lightning()
|
||||||
addr = self.wallet.create_new_address(False)
|
msg = [
|
||||||
|
_('No more unused addresses in your wallet.'),
|
||||||
|
_('All your addresses are used by unpaid requests.'),
|
||||||
|
]
|
||||||
|
msg.append(_('Do you wish to create a lightning-only request?') if has_lightning else _('Do you want to reuse an address?'))
|
||||||
|
return
|
||||||
|
|
||||||
req_key = self.wallet.create_request(amount, message, expiration, addr)
|
req_key = self.wallet.create_request(amount, message, expiration, addr)
|
||||||
self._logger.debug(f'created request with key {req_key}')
|
self._logger.debug(f'created request with key {req_key} addr {addr}')
|
||||||
#try:
|
|
||||||
#self.wallet.add_payment_request(req)
|
|
||||||
#except Exception as e:
|
|
||||||
#self.logger.exception('Error adding payment request')
|
|
||||||
#self.requestCreateError.emit('fatal',_('Error adding payment request') + ':\n' + repr(e))
|
|
||||||
#else:
|
|
||||||
## TODO: check this flow. Only if alias is defined in config. OpenAlias?
|
|
||||||
#pass
|
|
||||||
##self.sign_payment_request(addr)
|
|
||||||
|
|
||||||
return req_key, addr
|
return req_key
|
||||||
|
|
||||||
def _delete_expired_requests(self):
|
def _delete_expired_requests(self):
|
||||||
keys = self.wallet.delete_expired_requests()
|
keys = self.wallet.delete_expired_requests()
|
||||||
@@ -620,46 +607,14 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
@pyqtSlot(QEAmount, str, int, bool)
|
@pyqtSlot(QEAmount, str, int, bool)
|
||||||
@pyqtSlot(QEAmount, str, int, bool, bool)
|
@pyqtSlot(QEAmount, str, int, bool, bool)
|
||||||
@pyqtSlot(QEAmount, str, int, bool, bool, bool)
|
@pyqtSlot(QEAmount, str, int, bool, bool, bool)
|
||||||
def createRequest(self, amount: QEAmount, message: str, expiration: int, ignore_gap: bool = False, reuse_address: bool = False):
|
def createRequest(self, amount: QEAmount, message: str, expiration: int, lightning_only: bool = False, reuse_address: bool = False):
|
||||||
self._delete_expired_requests()
|
self._delete_expired_requests()
|
||||||
try:
|
try:
|
||||||
if self.wallet.lnworker and self.wallet.lnworker.channels:
|
key = self.create_bitcoin_request(amount.satsInt, message, expiration, lightning_only=lightning_only, reuse_address=reuse_address)
|
||||||
# TODO maybe show a warning if amount exceeds lnworker.num_sats_can_receive (as in kivy)
|
if not key:
|
||||||
# TODO fallback address robustness
|
self.requestCreateError.emit('ln' if self.wallet.has_lightning() else 'reuse_addr', ' '.join(msg))
|
||||||
addr = self.wallet.get_unused_address()
|
return
|
||||||
key = self.wallet.create_request(amount.satsInt, message, expiration, addr)
|
self.addressModel.setDirty()
|
||||||
else:
|
|
||||||
key, addr = self.create_bitcoin_request(amount.satsInt, message, expiration, ignore_gap=ignore_gap, reuse_address=reuse_address)
|
|
||||||
if not key:
|
|
||||||
return
|
|
||||||
self.addressModel.setDirty()
|
|
||||||
except InvoiceError as e:
|
|
||||||
self.requestCreateError.emit('fatal',_('Error creating payment request') + ':\n' + str(e))
|
|
||||||
return
|
|
||||||
|
|
||||||
assert key is not None
|
|
||||||
self.requestModel.add_invoice(self.wallet.get_request(key))
|
|
||||||
self.requestCreateSuccess.emit(key)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
@pyqtSlot(bool)
|
|
||||||
@pyqtSlot(bool, bool)
|
|
||||||
def createDefaultRequest(self, ignore_gap: bool = False, reuse_address: bool = False):
|
|
||||||
self._delete_expired_requests()
|
|
||||||
try:
|
|
||||||
default_expiry = self.wallet.config.get('request_expiry', PR_DEFAULT_EXPIRATION_WHEN_CREATING)
|
|
||||||
if self.wallet.lnworker and self.wallet.lnworker.channels:
|
|
||||||
addr = self.wallet.get_unused_address()
|
|
||||||
# if addr is None, we ran out of addresses
|
|
||||||
if addr is None:
|
|
||||||
# TODO: remove oldest unpaid request having a fallback address and try again
|
|
||||||
pass
|
|
||||||
key = self.wallet.create_request(None, None, default_expiry, addr)
|
|
||||||
else:
|
|
||||||
req = self.create_bitcoin_request(None, None, default_expiry, ignore_gap=ignore_gap, reuse_address=reuse_address)
|
|
||||||
if not req:
|
|
||||||
return
|
|
||||||
key, addr = req
|
|
||||||
except InvoiceError as e:
|
except InvoiceError as e:
|
||||||
self.requestCreateError.emit('fatal',_('Error creating payment request') + ':\n' + str(e))
|
self.requestCreateError.emit('fatal',_('Error creating payment request') + ':\n' + str(e))
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user