handle jit invoices in qml
make min funding amount symbol, change Signal name, change Exception type change minChannelFunding to QEAmount and make message text variable qml: improve translatibility of strings init minchannelfunding value in init method rebase on master
This commit is contained in:
@@ -106,10 +106,42 @@ ElDialog {
|
||||
}
|
||||
FlatButton {
|
||||
Layout.fillWidth: true
|
||||
enabled: Daemon.currentWallet.isLightning && Daemon.currentWallet.lightningCanReceive.satsInt > amountBtc.textAsSats.satsInt
|
||||
enabled: Daemon.currentWallet.isLightning && (Daemon.currentWallet.lightningCanReceive.satsInt
|
||||
> amountBtc.textAsSats.satsInt || Daemon.currentWallet.canGetZeroconfChannel)
|
||||
text: qsTr('Lightning')
|
||||
icon.source: '../../icons/lightning.png'
|
||||
onClicked: { dialog.isLightning = true; doAccept() }
|
||||
onClicked: {
|
||||
if (Daemon.currentWallet.lightningCanReceive.satsInt > amountBtc.textAsSats.satsInt) {
|
||||
// can receive on existing channel
|
||||
dialog.isLightning = true
|
||||
doAccept()
|
||||
} else if (Daemon.currentWallet.canGetZeroconfChannel && amountBtc.textAsSats.satsInt
|
||||
>= Daemon.currentWallet.minChannelFunding.satsInt) {
|
||||
// ask for confirmation of zeroconf channel to prevent fee surprise
|
||||
var confirmdialog = app.messageDialog.createObject(dialog, {
|
||||
title: qsTr('Confirm just-in-time channel'),
|
||||
text: [qsTr('Receiving this payment will purchase a Lightning channel from your service provider.'),
|
||||
qsTr('Fees will be deducted from the payment.'),
|
||||
qsTr('Do you want to continue?')].join(' '),
|
||||
yesno: true
|
||||
})
|
||||
confirmdialog.accepted.connect(function () {
|
||||
dialog.isLightning = true
|
||||
doAccept()
|
||||
})
|
||||
confirmdialog.open()
|
||||
} else {
|
||||
// show error that amnt > 200k is neccessary to get zeroconf channel
|
||||
var confirmdialog = app.messageDialog.createObject(dialog, {
|
||||
title: qsTr("Amount too low"),
|
||||
text: [qsTr("You don't have channels with enough inbound liquidity to receive this payment."),
|
||||
qsTr("Request at least %1 to open a channel just-in-time.").arg(
|
||||
Config.formatSats(Daemon.currentWallet.minChannelFunding.satsInt, true))].join(' ')
|
||||
})
|
||||
confirmdialog.open()
|
||||
}
|
||||
// can't get zeroconf channel and doesn't have enough inbound liquidity
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, py
|
||||
from electrum.logging import get_logger
|
||||
from electrum.invoices import (PR_UNPAID, PR_EXPIRED, PR_UNKNOWN, PR_PAID, PR_INFLIGHT,
|
||||
PR_FAILED, PR_ROUTING, PR_UNCONFIRMED, LN_EXPIRY_NEVER)
|
||||
from electrum.lnutil import MIN_FUNDING_SAT
|
||||
|
||||
from .qewallet import QEWallet
|
||||
from .qetypes import QEAmount
|
||||
@@ -118,9 +119,13 @@ class QERequestDetails(QObject, QtEventListener):
|
||||
|
||||
@pyqtProperty(str, notify=detailsChanged)
|
||||
def bolt11(self):
|
||||
can_receive = self._wallet.wallet.lnworker.num_sats_can_receive() if self._wallet.wallet.lnworker else 0
|
||||
if self._req and can_receive > 0 and (self._req.get_amount_sat() or 0) <= can_receive:
|
||||
bolt11 = self._wallet.wallet.get_bolt11_invoice(self._req)
|
||||
wallet = self._wallet.wallet
|
||||
amount_sat = self._req.get_amount_sat() or 0 if self._req else 0
|
||||
can_receive = wallet.lnworker.num_sats_can_receive() if wallet.lnworker else 0
|
||||
will_req_zeroconf = wallet.lnworker.receive_requires_jit_channel(amount_msat=amount_sat*1000)
|
||||
if self._req and ((can_receive > 0 and amount_sat <= can_receive)
|
||||
or (will_req_zeroconf and amount_sat >= MIN_FUNDING_SAT)):
|
||||
bolt11 = wallet.get_bolt11_invoice(self._req)
|
||||
else:
|
||||
return ''
|
||||
# encode lightning invoices as uppercase so QR encoding can use
|
||||
|
||||
@@ -15,6 +15,7 @@ from electrum.network import TxBroadcastError, BestEffortRequestFailed
|
||||
from electrum.transaction import PartialTransaction, Transaction
|
||||
from electrum.util import InvalidPassword, event_listener, AddTransactionException, get_asyncio_loop, NotEnoughFunds, \
|
||||
NoDynamicFeeEstimates
|
||||
from electrum.lnutil import MIN_FUNDING_SAT
|
||||
from electrum.plugin import run_hook
|
||||
from electrum.wallet import Multisig_Wallet
|
||||
from electrum.crypto import pw_decode_with_version_and_mac
|
||||
@@ -26,6 +27,7 @@ from .qeinvoicelistmodel import QEInvoiceListModel, QERequestListModel
|
||||
from .qetransactionlistmodel import QETransactionListModel
|
||||
from .qetypes import QEAmount
|
||||
from .util import QtEventListener, qt_event_listener
|
||||
from ...lntransport import extract_nodeid
|
||||
from ...fee_policy import FeePolicy
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -101,6 +103,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
self._frozenbalance = QEAmount()
|
||||
self._totalbalance = QEAmount()
|
||||
self._lightningcanreceive = QEAmount()
|
||||
self._minchannelfunding = QEAmount(amount_sat=int(MIN_FUNDING_SAT))
|
||||
self._lightningcansend = QEAmount()
|
||||
self._lightningbalancefrozen = QEAmount()
|
||||
|
||||
@@ -459,6 +462,11 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
def canSignMessage(self):
|
||||
return not isinstance(self.wallet, Multisig_Wallet) and not self.wallet.is_watching_only()
|
||||
|
||||
canGetZeroconfChannelChanged = pyqtSignal()
|
||||
@pyqtProperty(bool, notify=canGetZeroconfChannelChanged)
|
||||
def canGetZeroconfChannel(self) -> bool:
|
||||
return self.wallet.lnworker and self.wallet.lnworker.can_get_zeroconf_channel()
|
||||
|
||||
@pyqtProperty(QEAmount, notify=balanceChanged)
|
||||
def frozenBalance(self):
|
||||
c, u, x = self.wallet.get_frozen_balance()
|
||||
@@ -506,6 +514,10 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
self._lightningcanreceive.satsInt = int(self.wallet.lnworker.num_sats_can_receive())
|
||||
return self._lightningcanreceive
|
||||
|
||||
@pyqtProperty(QEAmount, notify=dataChanged)
|
||||
def minChannelFunding(self):
|
||||
return self._minchannelfunding
|
||||
|
||||
@pyqtProperty(int, notify=peersUpdated)
|
||||
def lightningNumPeers(self):
|
||||
if self.isLightning:
|
||||
|
||||
@@ -2193,7 +2193,7 @@ class LNWallet(LNWorker):
|
||||
timestamp = int(time.time())
|
||||
needs_jit: bool = self.receive_requires_jit_channel(amount_msat)
|
||||
routing_hints = self.calc_routing_hints_for_invoice(amount_msat, channels=channels, needs_jit=needs_jit)
|
||||
self.logger.info(f"creating bolt11 invoice with routing_hints: {routing_hints}, jit: {needs_jit}")
|
||||
self.logger.info(f"creating bolt11 invoice with routing_hints: {routing_hints}, jit: {needs_jit}, sat: {amount_msat or 0 // 1000}")
|
||||
invoice_features = self.features.for_invoice()
|
||||
if not self.uses_trampoline():
|
||||
invoice_features &= ~ LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
|
||||
@@ -2756,10 +2756,8 @@ class LNWallet(LNWorker):
|
||||
"""Returns true if we cannot receive the amount and have set up a trusted LSP node.
|
||||
Cannot work reliably with 0 amount invoices as we don't know if we are able to receive it.
|
||||
"""
|
||||
# a trusted zeroconf node is configured
|
||||
if (self.config.ZEROCONF_TRUSTED_NODE
|
||||
# the zeroconf node is a peer, it doesn't make sense to request a channel from an offline LSP
|
||||
and extract_nodeid(self.config.ZEROCONF_TRUSTED_NODE)[0] in self.peers
|
||||
# zeroconf provider is configured and connected
|
||||
if (self.can_get_zeroconf_channel()
|
||||
# we cannot receive the amount specified
|
||||
and ((amount_msat and self.num_sats_can_receive() < (amount_msat // 1000))
|
||||
# or we cannot receive anything, and it's a 0 amount invoice
|
||||
@@ -2767,6 +2765,18 @@ class LNWallet(LNWorker):
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_get_zeroconf_channel(self) -> bool:
|
||||
if not self.config.ACCEPT_ZEROCONF_CHANNELS and self.config.ZEROCONF_TRUSTED_NODE:
|
||||
# check if zeroconf is accepted and client has trusted zeroconf node configured
|
||||
return False
|
||||
try:
|
||||
node_id = extract_nodeid(self.wallet.config.ZEROCONF_TRUSTED_NODE)[0]
|
||||
except ConnStringFormatError:
|
||||
# invalid connection string
|
||||
return False
|
||||
# only return True if we are connected to the zeroconf provider
|
||||
return node_id in self.peers
|
||||
|
||||
def _suggest_channels_for_rebalance(self, direction, amount_sat) -> Sequence[Tuple[Channel, int]]:
|
||||
"""
|
||||
Suggest a channel and amount to send/receive with that channel, so that we will be able to receive/send amount_sat
|
||||
|
||||
Reference in New Issue
Block a user