Skip to content

Commit fdb4794

Browse files
committed
add zeroconf handling to qt gui
1 parent 4917f7e commit fdb4794

File tree

2 files changed

+55
-12
lines changed

2 files changed

+55
-12
lines changed

electrum/gui/qt/receive_tab.py

+21-4
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ def __init__(self, window: 'ElectrumWindow'):
9898
self.receive_help_text.setLayout(QHBoxLayout())
9999
self.receive_rebalance_button = QPushButton('Rebalance')
100100
self.receive_rebalance_button.suggestion = None
101+
self.receive_zeroconf_button = QPushButton(_('Accept'))
102+
self.receive_zeroconf_button.clicked.connect(self.on_accept_zeroconf)
101103

102104
def on_receive_rebalance():
103105
if self.receive_rebalance_button.suggestion:
@@ -115,6 +117,7 @@ def on_receive_swap():
115117
buttons = QHBoxLayout()
116118
buttons.addWidget(self.receive_rebalance_button)
117119
buttons.addWidget(self.receive_swap_button)
120+
buttons.addWidget(self.receive_zeroconf_button)
118121
vbox = QVBoxLayout()
119122
vbox.addWidget(self.receive_help_text)
120123
vbox.addLayout(buttons)
@@ -236,26 +239,37 @@ def update_current_request(self):
236239
self.ln_help = help_texts.ln_help
237240
can_rebalance = help_texts.can_rebalance()
238241
can_swap = help_texts.can_swap()
242+
can_zeroconf = help_texts.can_zeroconf()
239243
self.receive_rebalance_button.suggestion = help_texts.ln_rebalance_suggestion
240244
self.receive_swap_button.suggestion = help_texts.ln_swap_suggestion
241245
self.receive_rebalance_button.setVisible(can_rebalance)
242246
self.receive_swap_button.setVisible(can_swap)
243247
self.receive_rebalance_button.setEnabled(can_rebalance and self.window.num_tasks() == 0)
244248
self.receive_swap_button.setEnabled(can_swap and self.window.num_tasks() == 0)
249+
self.receive_zeroconf_button.setVisible(can_zeroconf)
250+
self.receive_zeroconf_button.setEnabled(can_zeroconf)
245251
text, data, help_text, title = self.get_tab_data()
246252
self.receive_e.setText(text)
247253
self.receive_qr.setData(data)
248254
self.receive_help_text.setText(help_text)
249255
for w in [self.receive_e, self.receive_qr]:
250-
w.setEnabled(bool(text) and not help_text)
256+
w.setEnabled(bool(text) and (not help_text or can_zeroconf))
251257
w.setToolTip(help_text)
252258
# macOS hack (similar to #4777)
253259
self.receive_e.repaint()
254260
# always show
261+
if can_zeroconf:
262+
# show the help message if zeroconf so user can first accept it and still sees the invoice
263+
# after accepting
264+
self.receive_widget.show_help()
255265
self.receive_widget.setVisible(True)
256266
self.toggle_qr_button.setEnabled(True)
257267
self.update_receive_qr_window()
258268

269+
def on_accept_zeroconf(self):
270+
self.receive_zeroconf_button.setVisible(False)
271+
self.update_receive_widgets()
272+
259273
def get_tab_data(self):
260274
if self.URI:
261275
out = self.URI, self.URI, self.URI_help, _('Bitcoin URI')
@@ -374,9 +388,12 @@ def update_visibility(self, is_qr):
374388
self.textedit.setVisible(not is_qr)
375389
self.qr.setVisible(is_qr)
376390
else:
377-
self.help_widget.setVisible(True)
378-
self.textedit.setVisible(False)
379-
self.qr.setVisible(False)
391+
self.show_help()
392+
393+
def show_help(self):
394+
self.help_widget.setVisible(True)
395+
self.textedit.setVisible(False)
396+
self.qr.setVisible(False)
380397

381398
def resizeEvent(self, e):
382399
# keep square aspect ratio when resized

electrum/wallet.py

+34-8
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,13 @@
5454
from .bip32 import BIP32Node, convert_bip32_intpath_to_strpath, convert_bip32_strpath_to_intpath
5555
from .crypto import sha256
5656
from . import util
57+
from .lntransport import extract_nodeid
5758
from .util import (NotEnoughFunds, UserCancelled, profiler, OldTaskGroup, ignore_exceptions,
5859
format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
5960
WalletFileException, BitcoinException,
6061
InvalidPassword, format_time, timestamp_to_datetime, Satoshis,
6162
Fiat, bfh, TxMinedInfo, quantize_feerate, OrderedDictWithIndex)
63+
from .lnutil import MIN_FUNDING_SAT
6264
from .simple_config import SimpleConfig, FEE_RATIO_HIGH_WARNING, FEERATE_WARNING_HIGH_FEE
6365
from .bitcoin import COIN, TYPE_ADDRESS
6466
from .bitcoin import is_address, address_to_script, is_minikey, relayfee, dust_threshold
@@ -350,13 +352,17 @@ class ReceiveRequestHelp(NamedTuple):
350352

351353
ln_swap_suggestion: Optional[Any] = None
352354
ln_rebalance_suggestion: Optional[Any] = None
355+
ln_zeroconf_suggestion: bool = False
353356

354357
def can_swap(self) -> bool:
355358
return bool(self.ln_swap_suggestion)
356359

357360
def can_rebalance(self) -> bool:
358361
return bool(self.ln_rebalance_suggestion)
359362

363+
def can_zeroconf(self) -> bool:
364+
return self.ln_zeroconf_suggestion
365+
360366

361367
class TxWalletDelta(NamedTuple):
362368
is_relevant: bool # "related to wallet?"
@@ -3278,12 +3284,19 @@ def get_help_texts_for_receive_request(self, req: Request) -> ReceiveRequestHelp
32783284
ln_is_error = False
32793285
ln_swap_suggestion = None
32803286
ln_rebalance_suggestion = None
3287+
ln_zeroconf_suggestion = False
32813288
URI = self.get_request_URI(req) or ''
32823289
lightning_has_channels = (
32833290
self.lnworker and len([chan for chan in self.lnworker.channels.values() if chan.is_open()]) > 0
32843291
)
32853292
lightning_online = self.lnworker and self.lnworker.num_peers() > 0
32863293
can_receive_lightning = self.lnworker and amount_sat <= self.lnworker.num_sats_can_receive()
3294+
try:
3295+
zeroconf_nodeid = extract_nodeid(self.config.ZEROCONF_TRUSTED_NODE)[0]
3296+
except Exception:
3297+
zeroconf_nodeid = None
3298+
can_get_zeroconf_channel = (self.lnworker and self.config.ACCEPT_ZEROCONF_CHANNELS
3299+
and zeroconf_nodeid in self.lnworker.peers)
32873300
status = self.get_invoice_status(req)
32883301

32893302
if status == PR_EXPIRED:
@@ -3309,21 +3322,33 @@ def get_help_texts_for_receive_request(self, req: Request) -> ReceiveRequestHelp
33093322
address_help = URI_help = (_("This address has already been used. "
33103323
"For better privacy, do not reuse it for new payments."))
33113324
if req.is_lightning():
3312-
if not lightning_has_channels:
3325+
if not lightning_has_channels and not can_get_zeroconf_channel:
33133326
ln_is_error = True
33143327
ln_help = _("You must have an open Lightning channel to receive payments.")
33153328
elif not lightning_online:
33163329
ln_is_error = True
33173330
ln_help = _('You must be online to receive Lightning payments.')
3318-
elif not can_receive_lightning:
3319-
ln_is_error = True
3331+
elif not can_receive_lightning or (amount_sat <= 0 and not lightning_has_channels):
33203332
ln_rebalance_suggestion = self.lnworker.suggest_rebalance_to_receive(amount_sat)
33213333
ln_swap_suggestion = self.lnworker.suggest_swap_to_receive(amount_sat)
3322-
ln_help = _('You do not have the capacity to receive this amount with Lightning.')
3323-
if bool(ln_rebalance_suggestion):
3324-
ln_help += '\n\n' + _('You may have that capacity if you rebalance your channels.')
3325-
elif bool(ln_swap_suggestion):
3326-
ln_help += '\n\n' + _('You may have that capacity if you swap some of your funds.')
3334+
# prefer to use swaps over JIT channels if possible
3335+
if can_get_zeroconf_channel and not bool(ln_rebalance_suggestion) and not bool(ln_swap_suggestion):
3336+
if amount_sat < MIN_FUNDING_SAT:
3337+
ln_is_error = True
3338+
ln_help = (_('Cannot receive this payment. Request at least {} sat '
3339+
'to purchase a Lightning channel from your service provider.')
3340+
.format(MIN_FUNDING_SAT))
3341+
else:
3342+
ln_zeroconf_suggestion = True
3343+
ln_help = _(f'Receiving this payment will purchase a payment channel from your '
3344+
f'service provider. Service fees are deducted from the incoming payment.')
3345+
else:
3346+
ln_is_error = True
3347+
ln_help = _('You do not have the capacity to receive this amount with Lightning.')
3348+
if bool(ln_rebalance_suggestion):
3349+
ln_help += '\n\n' + _('You may have that capacity if you rebalance your channels.')
3350+
elif bool(ln_swap_suggestion):
3351+
ln_help += '\n\n' + _('You may have that capacity if you swap some of your funds.')
33273352
# for URI that has LN part but no onchain part, copy error:
33283353
if not addr and ln_is_error:
33293354
URI_is_error = ln_is_error
@@ -3337,6 +3362,7 @@ def get_help_texts_for_receive_request(self, req: Request) -> ReceiveRequestHelp
33373362
ln_is_error=ln_is_error,
33383363
ln_rebalance_suggestion=ln_rebalance_suggestion,
33393364
ln_swap_suggestion=ln_swap_suggestion,
3365+
ln_zeroconf_suggestion=ln_zeroconf_suggestion
33403366
)
33413367

33423368

0 commit comments

Comments
 (0)