Skip to content

Commit ab8fa9e

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

File tree

3 files changed

+64
-5
lines changed

3 files changed

+64
-5
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/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import signal
2828
import sys
2929
import threading
30-
from typing import Optional, TYPE_CHECKING, List, Sequence
30+
from typing import Optional, TYPE_CHECKING, List, Sequence, Callable
3131

3232
try:
3333
import PyQt6

electrum/gui/qt/main_window.py

+57-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
@@ -267,6 +267,8 @@ def add_optional_tab(tabs, tab, icon, description):
267267

268268
# network callbacks
269269
self.register_callbacks()
270+
# wallet closing warning callbacks
271+
self.closing_warning_callbacks = [] # type: List[Callable[[], Optional[str]]]
270272
# banner may already be there
271273
if self.network and self.network.banner:
272274
self.console.showMessage(self.network.banner)
@@ -2612,8 +2614,52 @@ def settings_dialog(self):
26122614
if d.need_restart:
26132615
self.show_warning(_('Please restart Electrum to activate the new GUI settings'), title=_('Success'))
26142616

2617+
def _show_closing_warnings(self) -> bool:
2618+
"""Show any closing warnings and return True if the user chose to quit anyway."""
2619+
2620+
warnings: Set[str] = set()
2621+
for cb in self.closing_warning_callbacks:
2622+
if warning := cb():
2623+
warnings.add(warning)
2624+
2625+
for warning in list(warnings)[:3]:
2626+
warning = _("An ongoing operation prevents Electrum from closing:") + "\n\n" + warning
2627+
buttons = QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Close
2628+
result = self.show_warning(
2629+
msg=warning,
2630+
title=_("Don't close Electrum yet!"),
2631+
buttons=buttons,
2632+
defaultButton=QMessageBox.StandardButton.Cancel,
2633+
)
2634+
if result == QMessageBox.StandardButton.Cancel:
2635+
break
2636+
else:
2637+
# user chose to cancel all warnings or there were no warnings
2638+
return True
2639+
return False
2640+
2641+
def register_closing_warning_callback(self, callback: Callable[[], Optional[str]]) -> None:
2642+
"""
2643+
Registers a callback that will be called when the wallet is closed. If the callback
2644+
returns a string it will be shown to the user as a warning to prevent them closing the wallet.
2645+
"""
2646+
assert not asyncio.iscoroutinefunction(callback)
2647+
if not self.config.get("cmd") == "gui":
2648+
return
2649+
def warning_callback() -> Optional[str]:
2650+
try:
2651+
return callback()
2652+
except Exception:
2653+
self.logger.exception("Error in closing warning callback")
2654+
return None
2655+
self.logger.debug(f"registering wallet closing warning callback")
2656+
self.closing_warning_callbacks.append(warning_callback)
2657+
26152658
def closeEvent(self, event):
26162659
# note that closeEvent is NOT called if the user quits with Ctrl-C
2660+
if not self._show_closing_warnings():
2661+
event.ignore()
2662+
return
26172663
self.clean_up()
26182664
event.accept()
26192665

@@ -2797,7 +2843,16 @@ def on_swap_result(self, txid: Optional[str], *, is_reverse: bool):
27972843
if is_reverse:
27982844
msg += messages.MSG_REVERSE_SWAP_FUNDING_MEMPOOL
27992845
else:
2800-
msg += messages.MSG_FORWARD_SWAP_FUNDING_MEMPOOL
2846+
msg += messages.MSG_FORWARD_SWAP_FUNDING_MEMPOOL + messages.MSG_FORWARD_SWAP_HTLC_EXPIRY
2847+
2848+
def wallet_closing_warning_callback() -> Optional[str]:
2849+
# gets called when the wallet GUI is closed
2850+
warning = messages.MSG_REVERSE_SWAP_FUNDING_MEMPOOL if is_reverse \
2851+
else messages.MSG_FORWARD_SWAP_FUNDING_MEMPOOL
2852+
if self.wallet.adb.get_tx_height(txid).height < 1:
2853+
return _("Ongoing submarine swap") + ":\n" + warning
2854+
self.register_closing_warning_callback(wallet_closing_warning_callback)
2855+
28012856
self.show_message_signal.emit(msg)
28022857
else:
28032858
msg += _("Lightning funds were not received.") # FIXME should this not depend on is_reverse?

0 commit comments

Comments
 (0)