Browse Source

Rebalance dialog:

- move dialog code to own submodule and class
 - disable ok button if amount is out of bounds
 - add max button
 - add Rebalance button to channels tab
patch-4
ThomasV 3 years ago
parent
commit
8750936679
  1. 35
      electrum/gui/qt/channels_list.py
  2. 42
      electrum/gui/qt/main_window.py
  3. 69
      electrum/gui/qt/rebalance_dialog.py
  4. 3
      electrum/lnchannel.py
  5. 8
      electrum/lnworker.py

35
electrum/gui/qt/channels_list.py

@ -71,6 +71,7 @@ class ChannelsList(MyTreeView):
self.network = self.parent.network
self.wallet = self.parent.wallet
self.setSortingEnabled(True)
self.selectionModel().selectionChanged.connect(self.on_selection_changed)
@property
# property because lnworker might be initialized at runtime
@ -194,14 +195,8 @@ class ChannelsList(MyTreeView):
msg = messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP
self.main_window.show_warning(msg, title=_('Channel is frozen for sending'))
def create_menu(self, position):
menu = QMenu()
menu.setSeparatorsCollapsible(True) # consecutive separators are merged together
def get_rebalance_pair(self):
selected = self.selected_in_column(self.Columns.NODE_ALIAS)
if not selected:
menu.addAction(_("Import channel backup"), lambda: self.parent.do_process_from_text_channel_backup())
menu.exec_(self.viewport().mapToGlobal(position))
return
if len(selected) == 2:
idx1 = selected[0]
idx2 = selected[1]
@ -210,6 +205,28 @@ class ChannelsList(MyTreeView):
chan1 = self.lnworker.channels.get(channel_id1)
chan2 = self.lnworker.channels.get(channel_id2)
if chan1 and chan2 and (self.lnworker.channel_db or chan1.node_id != chan2.node_id):
return chan1, chan2
return None, None
def on_rebalance(self):
chan1, chan2 = self.get_rebalance_pair()
self.parent.rebalance_dialog(chan1, chan2)
def on_selection_changed(self):
chan1, chan2 = self.get_rebalance_pair()
self.rebalance_button.setEnabled(chan1 is not None)
def create_menu(self, position):
menu = QMenu()
menu.setSeparatorsCollapsible(True) # consecutive separators are merged together
selected = self.selected_in_column(self.Columns.NODE_ALIAS)
if not selected:
menu.addAction(_("Import channel backup"), lambda: self.parent.do_process_from_text_channel_backup())
menu.exec_(self.viewport().mapToGlobal(position))
return
if len(selected) == 2:
chan1, chan2 = self.get_rebalance_pair()
if chan1 and chan2:
menu.addAction(_("Rebalance"), lambda: self.parent.rebalance_dialog(chan1, chan2))
menu.exec_(self.viewport().mapToGlobal(position))
return
@ -356,12 +373,16 @@ class ChannelsList(MyTreeView):
self.can_send_label = QLabel('')
h.addWidget(self.can_send_label)
h.addStretch()
self.rebalance_button = EnterButton(_('Rebalance'), lambda x: self.on_rebalance())
self.rebalance_button.setToolTip("Select two active channels to rebalance.")
self.rebalance_button.setDisabled(True)
self.swap_button = EnterButton(_('Swap'), lambda x: self.parent.run_swap_dialog())
self.swap_button.setToolTip("Have at least one channel to do swaps.")
self.swap_button.setDisabled(True)
self.new_channel_button = EnterButton(_('Open Channel'), self.new_channel_with_warning)
self.new_channel_button.setEnabled(self.parent.wallet.has_lightning())
h.addWidget(self.new_channel_button)
h.addWidget(self.rebalance_button)
h.addWidget(self.swap_button)
return h

42
electrum/gui/qt/main_window.py

@ -3725,42 +3725,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.close()
def rebalance_dialog(self, chan1, chan2, amount_sat=None):
d = WindowModalDialog(self, _("Rebalance channels"))
d.reverse = False
vbox = QVBoxLayout(d)
vbox.addWidget(WWLabel(_('Rebalance your channels in order to increase your sending or receiving capacity') + ':'))
grid = QGridLayout()
amount_e = BTCAmountEdit(self.get_decimal_point)
amount_e.setAmount(amount_sat)
rev_button = QPushButton(u'\U000021c4')
label1 = QLabel('')
label2 = QLabel('')
def update():
if d.reverse:
d.chan_from = chan2
d.chan_to = chan1
else:
d.chan_from = chan1
d.chan_to = chan2
label1.setText(d.chan_from.short_id_for_GUI())
label2.setText(d.chan_to.short_id_for_GUI())
update()
def on_reverse():
d.reverse = not d.reverse
update()
rev_button.clicked.connect(on_reverse)
grid.addWidget(QLabel(_("From")), 0, 0)
grid.addWidget(label1, 0, 1)
grid.addWidget(QLabel(_("To")), 1, 0)
grid.addWidget(label2, 1, 1)
grid.addWidget(QLabel(_("Amount")), 2, 0)
grid.addWidget(amount_e, 2, 1)
grid.addWidget(rev_button, 0, 2)
vbox.addLayout(grid)
vbox.addLayout(Buttons(CancelButton(d), OkButton(d)))
if not d.exec_():
from .rebalance_dialog import RebalanceDialog
if chan1 is None or chan2 is None:
return
amount_msat = amount_e.get_amount() * 1000
coro = self.wallet.lnworker.rebalance_channels(d.chan_from, d.chan_to, amount_msat=amount_msat)
self.run_coroutine_from_thread(coro, _('Rebalancing channels'))
self.update_current_request() # this will gray out the button
d = RebalanceDialog(self, chan1, chan2, amount_sat)
d.run()

69
electrum/gui/qt/rebalance_dialog.py

@ -0,0 +1,69 @@
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton
from electrum.i18n import _
from .util import WindowModalDialog, Buttons, OkButton, CancelButton, WWLabel
from .amountedit import BTCAmountEdit
class RebalanceDialog(WindowModalDialog):
def __init__(self, window, chan1, chan2, amount_sat):
WindowModalDialog.__init__(self, window, _("Rebalance channels"))
self.window = window
self.wallet = window.wallet
self.chan1 = chan1
self.chan2 = chan2
vbox = QVBoxLayout(self)
vbox.addWidget(WWLabel(_('Rebalance your channels in order to increase your sending or receiving capacity') + ':'))
grid = QGridLayout()
self.amount_e = BTCAmountEdit(self.window.get_decimal_point)
self.amount_e.setAmount(amount_sat)
self.amount_e.textChanged.connect(self.on_amount)
self.rev_button = QPushButton(u'\U000021c4')
self.rev_button.clicked.connect(self.on_reverse)
self.max_button = QPushButton('Max')
self.max_button.clicked.connect(self.on_max)
self.label1 = QLabel('')
self.label2 = QLabel('')
self.ok_button = OkButton(self)
self.ok_button.setEnabled(False)
grid.addWidget(QLabel(_("From channel")), 0, 0)
grid.addWidget(self.label1, 0, 1)
grid.addWidget(QLabel(_("To channel")), 1, 0)
grid.addWidget(self.label2, 1, 1)
grid.addWidget(QLabel(_("Amount")), 2, 0)
grid.addWidget(self.amount_e, 2, 1)
grid.addWidget(self.max_button, 2, 2)
grid.addWidget(self.rev_button, 0, 2)
vbox.addLayout(grid)
vbox.addLayout(Buttons(CancelButton(self), self.ok_button))
self.update()
def on_reverse(self, x):
a, b = self.chan1, self.chan2
self.chan1, self.chan2 = b, a
self.amount_e.setAmount(None)
self.update()
def on_amount(self, x):
self.update()
def on_max(self, x):
n_sat = self.wallet.lnworker.num_sats_can_rebalance(self.chan1, self.chan2)
self.amount_e.setAmount(n_sat)
def update(self):
self.label1.setText(self.chan1.short_id_for_GUI())
self.label2.setText(self.chan2.short_id_for_GUI())
amount_sat = self.amount_e.get_amount()
b = bool(amount_sat) and self.wallet.lnworker.num_sats_can_rebalance(self.chan1, self.chan2) <= amount_sat
self.ok_button.setEnabled(b)
def run(self):
if not self.exec_():
return
amount_msat = self.amount_e.get_amount() * 1000
coro = self.wallet.lnworker.rebalance_channels(self.chan1, self.chan2, amount_msat=amount_msat)
self.window.run_coroutine_from_thread(coro, _('Rebalancing channels'))
self.window.update_current_request() # this will gray out the button

3
electrum/lnchannel.py

@ -558,6 +558,9 @@ class Channel(AbstractChannel):
forwarding_fee_base_msat = 1000
forwarding_fee_proportional_millionths = 1
def __repr__(self):
return "Channel(%s)"%self.get_id_for_log()
def __init__(self, state: 'StoredDict', *, sweep_address=None, name=None, lnworker=None, initial_feerate=None):
self.name = name
self.channel_id = bfh(state["channel_id"])

8
electrum/lnworker.py

@ -2232,6 +2232,14 @@ class LNWallet(LNWorker):
else:
return False
def num_sats_can_rebalance(self, chan1, chan2):
# TODO: we should be able to spend 'max', with variable fee
n1 = chan1.available_to_spend(LOCAL)
n1 -= self.fee_estimate(n1)
n2 = chan2.available_to_spend(REMOTE)
amount_sat = min(n1, n2) // 1000
return amount_sat
def suggest_rebalance_to_send(self, amount_sat):
return self._suggest_rebalance(SENT, amount_sat)

Loading…
Cancel
Save