2323# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2424# SOFTWARE.
2525
26- import asyncio
2726from decimal import Decimal
2827from functools import partial
2928from typing import TYPE_CHECKING , Optional , Union , Sequence
30- from concurrent .futures import Future
3129from enum import Enum , auto
3230
33- from PyQt6 .QtCore import Qt , QTimer , pyqtSlot , pyqtSignal
31+ from PyQt6 .QtCore import Qt , QTimer , pyqtSlot
3432from PyQt6 .QtGui import QIcon
3533from PyQt6 .QtWidgets import (QHBoxLayout , QVBoxLayout , QLabel , QGridLayout , QPushButton , QToolButton ,
3634 QComboBox , QTabWidget , QWidget , QStackedWidget )
3735
3836from electrum .i18n import _
3937from electrum .util import (UserCancelled , quantize_feerate , profiler , NotEnoughFunds , NoDynamicFeeEstimates ,
40- get_asyncio_loop , wait_for2 , UserFacingException )
38+ UserFacingException )
4139from electrum .plugin import run_hook
4240from electrum .transaction import PartialTransaction , PartialTxOutput , Transaction
4341from electrum .wallet import InternalAddressCorruption
4442from electrum .bitcoin import DummyAddress
4543from electrum .fee_policy import FeePolicy , FixedFeePolicy , FeeMethod
4644from electrum .logging import Logger
47- from electrum .submarine_swaps import NostrTransport , HttpTransport , SwapServerTransport , SwapServerError
45+ from electrum .submarine_swaps import NostrTransport , SwapServerError
4846from electrum .gui .messages import MSG_SUBMARINE_PAYMENT_HELP_TEXT
4947
50- from electrum .gui .common_qt .util import QtEventListener , qt_event_listener
48+ from electrum .gui .common_qt .util import qt_event_listener
49+ from electrum .gui .common_qt .swaps import SubmarineSwapMixin
5150
5251from .util import (WindowModalDialog , ColorScheme , HelpLabel , Buttons , CancelButton , WWLabel ,
5352 read_QIcon , IconLabel , HelpButton , RunCoroutineDialog )
@@ -71,9 +70,7 @@ class TxEditorContext(Enum):
7170 CHANNEL_FUNDING = auto ()
7271
7372
74- class TxEditor (WindowModalDialog , QtEventListener , Logger ):
75-
76- swap_availability_changed = pyqtSignal ()
73+ class TxEditor (WindowModalDialog , SubmarineSwapMixin , Logger ):
7774
7875 def __init__ (
7976 self , * , title = '' ,
@@ -87,6 +84,7 @@ def __init__(
8784
8885 WindowModalDialog .__init__ (self , window , title = title )
8986 Logger .__init__ (self )
87+ SubmarineSwapMixin .__init__ (self , window .create_sm_transport )
9088 self .main_window = window
9189 self .make_tx = make_tx
9290 self .output_value = output_value
@@ -109,9 +107,8 @@ def __init__(
109107 self ._base_tx = None # type: Optional[Transaction] # for batching
110108 self .batching_candidates = batching_candidates
111109
112- self .swap_manager = self .wallet .lnworker .swap_manager if self .wallet .has_lightning () else None
113- self .swap_transport = None # type: Optional[SwapServerTransport]
114- self .swap_availability_changed .connect (self .on_swap_availability_changed , Qt .ConnectionType .QueuedConnection )
110+ self .swapAvailabilityChanged .connect (self .on_swap_availability_changed , Qt .ConnectionType .QueuedConnection )
111+ self .set_wallet_for_swap (window .wallet )
115112 self .did_swap = False # used to clear the PI on send tab
116113
117114 self .locktime_e = LockTimeEdit (self )
@@ -168,25 +165,17 @@ def __init__(
168165 # debug_widget_layouts(self) # enable to show red lines around all elements
169166
170167 def accept (self ):
171- self ._cleanup ()
168+ self .swap_transport_cleanup ()
172169 super ().accept ()
173170
174171 def reject (self ):
175- self ._cleanup ()
172+ self .swap_transport_cleanup ()
176173 super ().reject ()
177174
178175 def closeEvent (self , event ):
179- self ._cleanup ()
176+ self .swap_transport_cleanup ()
180177 super ().closeEvent (event )
181178
182- def _cleanup (self ):
183- self .unregister_callbacks ()
184- if self .swap_transport and self .swap_transport .ongoing_connection_attempt :
185- self .swap_transport .ongoing_connection_attempt .cancel ()
186- if isinstance (self .swap_transport , NostrTransport ):
187- asyncio .run_coroutine_threadsafe (self .swap_transport .stop (), get_asyncio_loop ())
188- self .swap_transport = None # HTTPTransport doesn't need to be closed
189-
190179 def on_tab_changed (self , index ):
191180 if self .tab_widget .widget (index ) == self .submarine_payment_tab :
192181 self .prepare_swap_transport ()
@@ -742,67 +731,10 @@ def _update_send_button(self):
742731 def can_pay_assuming_zero_fees (self , confirmed_only : bool ) -> bool :
743732 raise NotImplementedError
744733
745- ### --- Shared functionality for submarine swaps (change to ln and submarine payments) ---
746- def prepare_swap_transport (self ):
747- if not self .swap_manager :
748- return # no swaps possible, lightning disabled
749- if self .swap_transport is not None :
750- if self .swap_transport .is_connected .is_set ():
751- # we already have a connected transport, no need to create a new one
752- return
753- if self .swap_transport .ongoing_connection_attempt :
754- # another task is currently trying to connect
755- return
756-
757- # there should only be a connected transport.
758- # a useless transport should get cleaned up and not stored.
759- assert self .swap_transport is None , "swap transport wasn't cleaned up properly"
760-
761- new_swap_transport = self .main_window .create_sm_transport ()
762- if not new_swap_transport :
763- # user declined to enable Nostr and has no http server configured
764- self .swap_availability_changed .emit ()
765- return
766-
767- async def _initialize_transport (transport ):
768- try :
769- if isinstance (transport , NostrTransport ):
770- asyncio .create_task (transport .main_loop ())
771- else :
772- assert isinstance (transport , HttpTransport )
773- asyncio .create_task (transport .get_pairs_just_once ())
774- if not await self .swap_manager .wait_for_swap_transport (transport ):
775- return
776- self .swap_transport = transport
777- except Exception :
778- self .logger .exception ("failed to create swap transport" )
779- finally :
780- self .swap_transport .ongoing_connection_attempt = None
781- self .swap_availability_changed .emit ()
782-
783- # this task will get cancelled if the TxEditor gets closed
784- self .swap_transport .ongoing_connection_attempt = asyncio .run_coroutine_threadsafe (
785- _initialize_transport (new_swap_transport ),
786- get_asyncio_loop (),
787- )
788-
789- @qt_event_listener
790- def on_event_swap_provider_changed (self ):
791- self .swap_availability_changed .emit ()
792-
793- @qt_event_listener
794- def on_event_channel (self , wallet , _channel ):
795- # useful e.g. if the user quickly opens the tab after startup before the channels are initialized
796- if wallet == self .wallet and self .swap_manager and self .swap_manager .is_initialized .is_set ():
797- self .swap_availability_changed .emit ()
798-
799734 @qt_event_listener
800735 def on_event_swap_offers_changed (self , _ ):
801736 self .change_to_ln_swap_providers_button .update ()
802737 self .submarine_payment_provider_button .update ()
803- if self .swap_transport and self .swap_transport .ongoing_connection_attempt :
804- return
805- self .swap_availability_changed .emit ()
806738
807739 @pyqtSlot ()
808740 def on_swap_availability_changed (self ):
0 commit comments