diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index cc692ba73..6c568fe09 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -99,7 +99,7 @@ from .channels_list import ChannelsList from .confirm_tx_dialog import ConfirmTxDialog from .rbf_dialog import BumpFeeDialog, DSCancelDialog from .qrreader import scan_qrcode -from .swap_dialog import SwapDialog +from .swap_dialog import SwapDialog, InvalidSwapParameters from .balance_dialog import BalanceToolButton, COLOR_FROZEN, COLOR_UNMATURED, COLOR_UNCONFIRMED, COLOR_CONFIRMED, COLOR_LIGHTNING, COLOR_FROZEN_LIGHTNING if TYPE_CHECKING: @@ -1126,7 +1126,11 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): self.show_error(str(e)) return d = SwapDialog(self, is_reverse=is_reverse, recv_amount_sat=recv_amount_sat, channels=channels) - return d.run() + try: + return d.run() + except InvalidSwapParameters as e: + self.show_error(str(e)) + return @qt_event_listener def on_event_request_status(self, wallet, key, status): diff --git a/electrum/gui/qt/swap_dialog.py b/electrum/gui/qt/swap_dialog.py index 4f52756c6..a4686032c 100644 --- a/electrum/gui/qt/swap_dialog.py +++ b/electrum/gui/qt/swap_dialog.py @@ -20,17 +20,18 @@ from .my_treeview import create_toolbar_with_menu if TYPE_CHECKING: from .main_window import ElectrumWindow -CANNOT_RECEIVE_WARNING = """ -The requested amount is higher than what you can receive in your currently open channels. +CANNOT_RECEIVE_WARNING = _( +"""The requested amount is higher than what you can receive in your currently open channels. If you continue, your funds will be locked until the remote server can find a path to pay you. If the swap cannot be performed after 24h, you will be refunded. -Do you want to continue? -""" +Do you want to continue?""" +) -class SwapDialog(WindowModalDialog, QtEventListener): +class InvalidSwapParameters(Exception): pass + - tx: Optional[PartialTransaction] +class SwapDialog(WindowModalDialog, QtEventListener): def __init__(self, window: 'ElectrumWindow', is_reverse=None, recv_amount_sat=None, channels=None): WindowModalDialog.__init__(self, window, _('Submarine Swap')) @@ -231,7 +232,7 @@ class SwapDialog(WindowModalDialog, QtEventListener): self.server_fee_label.repaint() # macOS hack for #6269 self.needs_tx_update = True - def update_fee(self, tx): + def update_fee(self, tx: Optional[PartialTransaction]) -> None: """Updates self.fee_label. No other side-effects.""" if self.is_reverse: sm = self.swap_manager @@ -243,6 +244,7 @@ class SwapDialog(WindowModalDialog, QtEventListener): self.fee_label.repaint() # macOS hack for #6269 def run(self): + """Can raise InvalidSwapParameters.""" if not self.exec_(): return if self.is_reverse: @@ -273,24 +275,23 @@ class SwapDialog(WindowModalDialog, QtEventListener): return is_max = self.max_button.isChecked() if is_max: - tx = self._create_tx('!') + tx = self._create_tx_safe('!') self._spend_max_forward_swap(tx) else: onchain_amount = self.send_amount_e.get_amount() - tx = self._create_tx(onchain_amount) + tx = self._create_tx_safe(onchain_amount) self.update_fee(tx) - def _create_tx(self, onchain_amount: Union[int, str, None]) -> Optional[PartialTransaction]: - if self.is_reverse: - return + def _create_tx(self, onchain_amount: Union[int, str, None]) -> PartialTransaction: + assert not self.is_reverse if onchain_amount is None: - return + raise InvalidSwapParameters("onchain_amount is None") coins = self.window.get_coins() if onchain_amount == '!': max_amount = sum(c.value_sats() for c in coins) max_swap_amount = self.swap_manager.max_amount_forward_swap() if max_swap_amount is None: - return None + raise InvalidSwapParameters("swap_manager.max_amount_forward_swap() is None") if max_amount > max_swap_amount: onchain_amount = max_swap_amount outputs = [PartialTxOutput.from_address_and_value(ln_dummy_address(), onchain_amount)] @@ -299,9 +300,15 @@ class SwapDialog(WindowModalDialog, QtEventListener): coins=coins, outputs=outputs) except (NotEnoughFunds, NoDynamicFeeEstimates) as e: - return + raise InvalidSwapParameters(str(e)) from e return tx + def _create_tx_safe(self, onchain_amount: Union[int, str, None]) -> Optional[PartialTransaction]: + try: + return self._create_tx(onchain_amount=onchain_amount) + except InvalidSwapParameters: + return None + def update_ok_button(self): """Updates self.ok_button. No other side-effects.""" send_amount = self.send_amount_e.get_amount()