Qt: move LN fee slider to payment dialog. fixes #10516
What changed, and why it matters
This commit simply moves a user-interface slider for setting the maximum Lightning Network routing fee from the Settings window into the payment confirmation dialog. It is a usability improvement, not a security fix. There is no change to how payments are authorized, no new code path that could steal funds, and no vulnerability being patched.
No security action required. Treat as a normal UI/UX change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch removes the LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS slider from settings_dialog.py and adds an equivalent slider to the Lightning invoice payment confirmation dialog in send_tab.py. The same config variable is read and written, the same discrete fee map is used, and the same label formatting logic is preserved. The dialog is modal and still requires the user to click Pay to proceed. No cryptographic, network, or wallet logic is modified.
Changed components
electrum/gui/qt/send_tab.pyelectrum/gui/qt/settings_dialog.pyInspect captured patch +45 / −40
diff --git a/electrum/gui/qt/send_tab.py b/electrum/gui/qt/send_tab.py
index 10d2c3d..cdb97cc 100644
--- a/electrum/gui/qt/send_tab.py
+++ b/electrum/gui/qt/send_tab.py
@@ -8,7 +8,7 @@ import urllib.parse
from PyQt6.QtCore import pyqtSignal, QPoint, Qt
from PyQt6.QtWidgets import (QLabel, QVBoxLayout, QGridLayout, QHBoxLayout,
- QWidget, QToolTip, QPushButton, QApplication)
+ QWidget, QToolTip, QPushButton, QApplication, QSlider)
from electrum.i18n import _
from electrum.logging import Logger
@@ -157,12 +157,6 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
self.send_button.setEnabled(False)
self.clear_button = EnterButton(_("Clear"), self.do_clear)
- #buttons1 = QHBoxLayout()
- #buttons1.addWidget(self.paste_button)
- #buttons1.addWidget(self.clear_button)
- #buttons1.addStretch(1)
- #grid.addLayout(buttons1, 0, 1, 1, 4)
-
buttons = QHBoxLayout()
buttons.addWidget(self.paste_button)
buttons.addWidget(self.clear_button)
@@ -728,8 +722,49 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
assert lnworker is not None
# FIXME this is currently lying to user as we truncate to satoshis
amount_msat = invoice.get_amount_msat()
- msg = _("Pay lightning invoice?") + '\n\n' + _("This will send {}?").format(self.format_amount_and_units(Decimal(amount_msat)/1000))
- if not self.question(msg):
+ label = QLabel(
+ _("This will send {} to the recipient").format(self.format_amount_and_units(Decimal(amount_msat)/1000)))
+
+ dialog = WindowModalDialog(self, _("Pay lightning invoice?"))
+ dialog.setMinimumWidth(400)
+ vbox = QVBoxLayout()
+ dialog.setLayout(vbox)
+ vbox.addWidget(label)
+ vbox.addStretch(1)
+
+ lnfee_hlabel = HelpLabel.from_configvar(self.config.cv.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS)
+ lnfee_hlabel.setText(_('Max routing fee') + ' :')
+ lnfee_map = [500, 1_000, 3_000, 5_000, 10_000, 20_000, 30_000, 50_000]
+ def lnfee_update_vlabel(fee_val: int):
+ lnfee_vlabel.setText(_("{}% of payment").format(f"{fee_val / 10 ** 4:.2f}"))
+ def lnfee_slider_moved():
+ pos = lnfee_slider.sliderPosition()
+ fee_val = lnfee_map[pos]
+ lnfee_update_vlabel(fee_val)
+ self.config.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS = fee_val
+ lnfee_slider = QSlider(Qt.Orientation.Horizontal)
+ lnfee_slider.setRange(0, len(lnfee_map)-1)
+ lnfee_slider.setTracking(True)
+ try:
+ lnfee_spos = lnfee_map.index(self.config.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS)
+ except ValueError:
+ lnfee_spos = 0
+ lnfee_slider.setSliderPosition(lnfee_spos)
+ lnfee_vlabel = QLabel("")
+ lnfee_update_vlabel(self.config.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS)
+ lnfee_slider.valueChanged.connect(lnfee_slider_moved)
+ grid = QGridLayout()
+ grid.setSpacing(8)
+ grid.setColumnStretch(3, 1) # Make the last column stretch
+ grid.addWidget(lnfee_hlabel, 0, 0)
+ grid.addWidget(lnfee_vlabel, 0, 1)
+ grid.addWidget(lnfee_slider, 1, 1)
+ vbox.addLayout(grid)
+
+ pay_button = OkButton(dialog, _("Pay"))
+ cancel_button = CancelButton(dialog)
+ vbox.addLayout(Buttons(cancel_button, pay_button))
+ if not dialog.exec():
return
self.save_pending_invoice()
coro = lnworker.pay_invoice(invoice, amount_msat=amount_msat)
diff --git a/electrum/gui/qt/settings_dialog.py b/electrum/gui/qt/settings_dialog.py
index 1655e17..6b41126 100644
--- a/electrum/gui/qt/settings_dialog.py
+++ b/electrum/gui/qt/settings_dialog.py
@@ -29,7 +29,7 @@ from typing import TYPE_CHECKING, Dict
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (QComboBox, QTabWidget, QDialog, QSpinBox, QCheckBox, QLabel,
- QVBoxLayout, QGridLayout, QLineEdit, QWidget, QHBoxLayout, QSlider)
+ QVBoxLayout, QGridLayout, QLineEdit, QWidget, QHBoxLayout)
from electrum.i18n import _, get_gui_lang_names
from electrum import util
@@ -137,35 +137,6 @@ class SettingsDialog(QDialog, QtEventListener):
util.trigger_callback('channels_updated', self.wallet)
trampoline_cb.stateChanged.connect(on_trampoline_checked)
- lnfee_hlabel = HelpLabel.from_configvar(self.config.cv.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS)
- lnfee_map = [500, 1_000, 3_000, 5_000, 10_000, 20_000, 30_000, 50_000]
-
- def lnfee_update_vlabel(fee_val: int):
- lnfee_vlabel.setText(_("{}% of payment").format(f"{fee_val / 10 ** 4:.2f}"))
-
- def lnfee_slider_moved():
- pos = lnfee_slider.sliderPosition()
- fee_val = lnfee_map[pos]
- lnfee_update_vlabel(fee_val)
- self.config.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS = fee_val
-
- lnfee_slider = QSlider(Qt.Orientation.Horizontal)
- lnfee_slider.setRange(0, len(lnfee_map)-1)
- lnfee_slider.setTracking(True)
- try:
- lnfee_spos = lnfee_map.index(self.config.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS)
- except ValueError:
- lnfee_spos = 0
- lnfee_slider.setSliderPosition(lnfee_spos)
- lnfee_vlabel = QLabel("")
- lnfee_update_vlabel(self.config.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS)
- lnfee_slider.valueChanged.connect(lnfee_slider_moved)
- lnfee_hbox = QHBoxLayout()
- lnfee_hbox.setContentsMargins(0, 0, 0, 0)
- lnfee_hbox.addWidget(lnfee_vlabel)
- lnfee_hbox.addWidget(lnfee_slider)
- lnfee_hbox_w = QWidget()
- lnfee_hbox_w.setLayout(lnfee_hbox)
alias_label = HelpLabel.from_configvar(self.config.cv.OPENALIAS_ID)
alias = self.config.OPENALIAS_ID
@@ -389,7 +360,6 @@ class SettingsDialog(QDialog, QtEventListener):
units_widgets.append((thousandsep_cb, None))
lightning_widgets = []
lightning_widgets.append((trampoline_cb, None))
- lightning_widgets.append((lnfee_hlabel, lnfee_hbox_w))
fiat_widgets = []
fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo))
fiat_widgets.append((QLabel(_('Source')), ex_combo))
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.