Skip to content

Commit d931825

Browse files
committed
add option to show warnings on wallet close, add warning for ongoing submarine swap
1 parent dfb7a8a commit d931825

File tree

3 files changed

+74
-4
lines changed

3 files changed

+74
-4
lines changed

electrum/gui/messages.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,15 @@ def to_rtf(msg):
6161
_("Please remain online until the funding transaction is confirmed.") + "\n\n" +
6262
_('The swap will be finalized once your transaction is confirmed.') + " " +
6363
_("After the funding transaction is mined, the server will reveal the preimage needed to "
64-
"fulfill the pending received lightning HTLCs. The HTLCs expire in {} blocks. "
64+
"fulfill the pending received lightning HTLCs.")
65+
)
66+
67+
MSG_FORWARD_SWAP_HTLC_EXPIRY = _(
68+
"The HTLCs expire in {} blocks. "
6569
"You will need to be online after the funding transaction is confirmed but before the HTLCs expire, "
6670
"to claim your money. If you go offline for several days while the swap is pending, "
6771
"you risk losing the swap amount!").format(MIN_FINAL_CLTV_DELTA_FOR_CLIENT)
68-
)
72+
6973

7074
MSG_REVERSE_SWAP_FUNDING_MEMPOOL = (
7175
_('The funding transaction has been detected.') + " " +

electrum/gui/qt/main_window.py

+59-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from functools import partial
3535
import queue
3636
import asyncio
37-
from typing import Optional, TYPE_CHECKING, Sequence, Union, Dict, Mapping
37+
from typing import Optional, TYPE_CHECKING, Sequence, Union, Dict, Mapping, Callable, List, Set
3838
import concurrent.futures
3939

4040
from PyQt6.QtGui import QPixmap, QKeySequence, QIcon, QCursor, QFont, QFontMetrics, QAction, QShortcut
@@ -271,6 +271,9 @@ def add_optional_tab(tabs, tab, icon, description):
271271

272272
# network callbacks
273273
self.register_callbacks()
274+
# wallet closing warning callbacks
275+
self.closing_warning_callbacks = [] # type: List[Callable[[], Optional[str]]]
276+
self.register_closing_warning_callback(self._check_ongoing_submarine_swaps_callback)
274277
# banner may already be there
275278
if self.network and self.network.banner:
276279
self.console.showMessage(self.network.banner)
@@ -2684,8 +2687,62 @@ def settings_dialog(self):
26842687
if d.need_restart:
26852688
self.show_warning(_('Please restart Electrum to activate the new GUI settings'), title=_('Success'))
26862689

2690+
def _show_closing_warnings(self) -> bool:
2691+
"""Show any closing warnings and return True if the user chose to quit anyway."""
2692+
2693+
warnings: Set[str] = set()
2694+
for cb in self.closing_warning_callbacks:
2695+
if warning := cb():
2696+
warnings.add(warning)
2697+
2698+
for warning in list(warnings)[:3]:
2699+
warning = _("An ongoing operation prevents Electrum from closing:") + "\n\n" + warning
2700+
buttons = QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Close
2701+
result = self.show_warning(
2702+
msg=warning,
2703+
title=_("Don't close Electrum yet!"),
2704+
buttons=buttons,
2705+
defaultButton=QMessageBox.StandardButton.Cancel,
2706+
)
2707+
if result == QMessageBox.StandardButton.Cancel:
2708+
break
2709+
else:
2710+
# user chose to cancel all warnings or there were no warnings
2711+
return True
2712+
return False
2713+
2714+
def register_closing_warning_callback(self, callback: Callable[[], Optional[str]]) -> None:
2715+
"""
2716+
Registers a callback that will be called when the wallet is closed. If the callback
2717+
returns a string it will be shown to the user as a warning to prevent them closing the wallet.
2718+
"""
2719+
assert not asyncio.iscoroutinefunction(callback)
2720+
def warning_callback() -> Optional[str]:
2721+
try:
2722+
return callback()
2723+
except Exception:
2724+
self.logger.exception("Error in closing warning callback")
2725+
return None
2726+
self.logger.debug(f"registering wallet closing warning callback")
2727+
self.closing_warning_callbacks.append(warning_callback)
2728+
2729+
def _check_ongoing_submarine_swaps_callback(self) -> Optional[str]:
2730+
"""Callback that will return a warning string if there is a unconfirmed swap funding."""
2731+
if not (self.wallet.has_lightning() and self.wallet.lnworker.swap_manager):
2732+
return None
2733+
if self.wallet.lnworker.swap_manager.has_pending_swaps():
2734+
return "\n".join((
2735+
_("Ongoing submarine swap:"),
2736+
_("Wait until the funding transaction of your swap confirms, "
2737+
"otherwise you risk losing funds.")
2738+
))
2739+
return None
2740+
26872741
def closeEvent(self, event):
26882742
# note that closeEvent is NOT called if the user quits with Ctrl-C
2743+
if not self._show_closing_warnings():
2744+
event.ignore()
2745+
return
26892746
self.clean_up()
26902747
event.accept()
26912748

@@ -2870,7 +2927,7 @@ def on_swap_result(self, txid: Optional[str], *, is_reverse: bool):
28702927
if is_reverse:
28712928
msg += messages.MSG_REVERSE_SWAP_FUNDING_MEMPOOL
28722929
else:
2873-
msg += messages.MSG_FORWARD_SWAP_FUNDING_MEMPOOL
2930+
msg += messages.MSG_FORWARD_SWAP_FUNDING_MEMPOOL + messages.MSG_FORWARD_SWAP_HTLC_EXPIRY
28742931
self.show_message_signal.emit(msg)
28752932
else:
28762933
msg += _("Lightning funds were not received.") # FIXME should this not depend on is_reverse?

electrum/submarine_swaps.py

+9
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,15 @@ def get_group_id_for_payment_hash(self, payment_hash):
12791279
if swap:
12801280
return swap.spending_txid if swap.is_reverse else swap.funding_txid
12811281

1282+
def has_pending_swaps(self) -> bool:
1283+
"""Returns True if there are swaps with unconfirmed funding tx (require us to stay online)."""
1284+
for swap in self.swaps.values():
1285+
if swap.funding_txid and not swap.is_redeemed:
1286+
# swap is funded but not marked redeemed by _claim_swap
1287+
if self.lnworker.wallet.adb.get_tx_height(swap.funding_txid).height < 1:
1288+
# funding TX is not yet confirmed, wallet should not be closed
1289+
return True
1290+
return False
12821291

12831292
class SwapServerTransport(Logger):
12841293

0 commit comments

Comments
 (0)