send tx change to lightning
This commit is contained in:
@@ -8,7 +8,8 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from electrum.i18n import _
|
||||
from electrum.gui import messages
|
||||
from electrum.util import bfh
|
||||
from electrum.lnutil import extract_nodeid, ln_dummy_address, ConnStringFormatError
|
||||
from electrum.lnutil import extract_nodeid, ConnStringFormatError
|
||||
from electrum.bitcoin import get_dummy_address
|
||||
from electrum.lnworker import hardcoded_trampoline_nodes
|
||||
from electrum.logging import get_logger
|
||||
|
||||
@@ -181,7 +182,7 @@ class QEChannelOpener(QObject, AuthMixin):
|
||||
"""
|
||||
self._logger.debug('opening channel')
|
||||
# read funding_sat from tx; converts '!' to int value
|
||||
funding_sat = funding_tx.output_value_for_address(ln_dummy_address())
|
||||
funding_sat = funding_tx.output_value_for_address(get_dummy_address('channel'))
|
||||
lnworker = self._wallet.wallet.lnworker
|
||||
|
||||
def open_thread():
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import Union
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, Q_ENUMS
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.lnutil import ln_dummy_address
|
||||
from electrum.bitcoin import get_dummy_address
|
||||
from electrum.logging import get_logger
|
||||
from electrum.transaction import PartialTxOutput
|
||||
from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates, profiler, get_asyncio_loop
|
||||
@@ -245,7 +245,7 @@ class QESwapHelper(AuthMixin, QObject, QtEventListener):
|
||||
# this is just to estimate the maximal spendable onchain amount for HTLC
|
||||
self.update_tx('!')
|
||||
try:
|
||||
max_onchain_spend = self._tx.output_value_for_address(ln_dummy_address())
|
||||
max_onchain_spend = self._tx.output_value_for_address(get_dummy_address('swap'))
|
||||
except AttributeError: # happens if there are no utxos
|
||||
max_onchain_spend = 0
|
||||
reverse = int(min(lnworker.num_sats_can_send(),
|
||||
@@ -283,7 +283,7 @@ class QESwapHelper(AuthMixin, QObject, QtEventListener):
|
||||
self._tx = None
|
||||
self.valid = False
|
||||
return
|
||||
outputs = [PartialTxOutput.from_address_and_value(ln_dummy_address(), onchain_amount)]
|
||||
outputs = [PartialTxOutput.from_address_and_value(get_dummy_address('swap'), onchain_amount)]
|
||||
coins = self._wallet.wallet.get_spendable_coins(None)
|
||||
try:
|
||||
self._tx = self._wallet.wallet.make_unsigned_transaction(
|
||||
|
||||
@@ -96,6 +96,7 @@ class TxEditor(WindowModalDialog):
|
||||
vbox.addLayout(grid)
|
||||
vbox.addWidget(self.io_widget)
|
||||
self.message_label = WWLabel('')
|
||||
self.message_label.setMinimumHeight(70)
|
||||
vbox.addWidget(self.message_label)
|
||||
|
||||
buttons = self.create_buttons_bar()
|
||||
@@ -395,6 +396,11 @@ class TxEditor(WindowModalDialog):
|
||||
self.toggle_locktime,
|
||||
_('Edit Locktime'), '')
|
||||
self.pref_menu.addSeparator()
|
||||
add_pref_action(
|
||||
self.config.WALLET_SEND_CHANGE_TO_LIGHTNING,
|
||||
self.toggle_send_change_to_lightning,
|
||||
_('Send change to Lightning'),
|
||||
_('If possible, send the change of this transaction to your channels, with a submarine swap'))
|
||||
add_pref_action(
|
||||
self.wallet.use_change,
|
||||
self.toggle_use_change,
|
||||
@@ -465,6 +471,11 @@ class TxEditor(WindowModalDialog):
|
||||
self.config.WALLET_BATCH_RBF = b
|
||||
self.trigger_update()
|
||||
|
||||
def toggle_send_change_to_lightning(self):
|
||||
b = not self.config.WALLET_SEND_CHANGE_TO_LIGHTNING
|
||||
self.config.WALLET_SEND_CHANGE_TO_LIGHTNING = b
|
||||
self.trigger_update()
|
||||
|
||||
def toggle_confirmed_only(self):
|
||||
b = not self.config.WALLET_SPEND_CONFIRMED_ONLY
|
||||
self.config.WALLET_SPEND_CONFIRMED_ONLY = b
|
||||
@@ -563,6 +574,8 @@ class TxEditor(WindowModalDialog):
|
||||
self.error = long_warning
|
||||
else:
|
||||
messages.append(long_warning)
|
||||
if self.tx.has_dummy_output('swap'):
|
||||
messages.append(_('This transaction will send funds to a submarine swap.'))
|
||||
# warn if spending unconf
|
||||
if any((txin.block_height is not None and txin.block_height<=0) for txin in self.tx.inputs()):
|
||||
messages.append(_('This transaction will spend unconfirmed coins.'))
|
||||
@@ -573,6 +586,9 @@ class TxEditor(WindowModalDialog):
|
||||
num_change = sum(int(o.is_change) for o in self.tx.outputs())
|
||||
if num_change > 1:
|
||||
messages.append(_('This transaction has {} change outputs.'.format(num_change)))
|
||||
if num_change == 0:
|
||||
messages.append(_('Make sure you pay enough mining fees; you will not be able to bump the fee later.'))
|
||||
|
||||
# TODO: warn if we send change back to input address
|
||||
return messages
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ import electrum
|
||||
from electrum.gui import messages
|
||||
from electrum import (keystore, ecc, constants, util, bitcoin, commands,
|
||||
paymentrequest, lnutil)
|
||||
from electrum.bitcoin import COIN, is_address
|
||||
from electrum.bitcoin import COIN, is_address, get_dummy_address
|
||||
from electrum.plugin import run_hook, BasePlugin
|
||||
from electrum.i18n import _
|
||||
from electrum.util import (format_time, UserCancelled, profiler, bfh, InvalidPassword,
|
||||
@@ -70,7 +70,7 @@ from electrum.network import Network, UntrustedServerReturnedError, NetworkExcep
|
||||
from electrum.exchange_rate import FxThread
|
||||
from electrum.simple_config import SimpleConfig
|
||||
from electrum.logging import Logger
|
||||
from electrum.lnutil import ln_dummy_address, extract_nodeid, ConnStringFormatError
|
||||
from electrum.lnutil import extract_nodeid, ConnStringFormatError
|
||||
from electrum.lnaddr import lndecode
|
||||
from electrum.submarine_swaps import SwapServerError
|
||||
|
||||
@@ -163,6 +163,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
computing_privkeys_signal = pyqtSignal()
|
||||
show_privkeys_signal = pyqtSignal()
|
||||
show_error_signal = pyqtSignal(str)
|
||||
show_message_signal = pyqtSignal(str)
|
||||
labels_changed_signal = pyqtSignal()
|
||||
|
||||
def __init__(self, gui_object: 'ElectrumGui', wallet: Abstract_Wallet):
|
||||
@@ -263,6 +264,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
self.app.update_fiat_signal.connect(self.update_fiat)
|
||||
|
||||
self.show_error_signal.connect(self.show_error)
|
||||
self.show_message_signal.connect(self.show_message)
|
||||
self.history_list.setFocus()
|
||||
|
||||
# network callbacks
|
||||
@@ -1236,6 +1238,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
'''Sign the transaction in a separate thread. When done, calls
|
||||
the callback with a success code of True or False.
|
||||
'''
|
||||
|
||||
def on_success(result):
|
||||
callback(True)
|
||||
def on_failure(exc_info):
|
||||
@@ -1279,7 +1282,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
@protected
|
||||
def _open_channel(self, connect_str, funding_sat, push_amt, funding_tx, password):
|
||||
# read funding_sat from tx; converts '!' to int value
|
||||
funding_sat = funding_tx.output_value_for_address(ln_dummy_address())
|
||||
funding_sat = funding_tx.output_value_for_address(get_dummy_address('channel'))
|
||||
def task():
|
||||
return self.wallet.lnworker.open_channel(
|
||||
connect_str=connect_str,
|
||||
@@ -2822,3 +2825,14 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
return
|
||||
d = RebalanceDialog(self, chan1, chan2, amount_sat)
|
||||
d.run()
|
||||
|
||||
def on_swap_result(self, txid):
|
||||
msg = _("Submarine swap") + ': ' + (_("Success") if txid else _("Expired")) + '\n\n'
|
||||
if txid:
|
||||
msg += _("Funding transaction") + ': ' + txid + '\n'
|
||||
msg += _("Please remain online until the funding transaction is confirmed.")
|
||||
self.show_message_signal.emit(msg)
|
||||
else:
|
||||
msg += _("Lightning funds were not received.")
|
||||
self.show_error_signal.emit(msg)
|
||||
|
||||
|
||||
@@ -325,6 +325,15 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
# user cancelled
|
||||
return
|
||||
is_preview = conf_dlg.is_preview
|
||||
|
||||
if tx.has_dummy_output('swap'):
|
||||
sm = self.wallet.lnworker.swap_manager
|
||||
coro = sm.request_swap_for_tx(tx)
|
||||
swap, invoice, tx = self.network.run_from_another_thread(coro)
|
||||
assert not tx.has_dummy_output('swap')
|
||||
tx.swap_invoice = invoice
|
||||
tx.swap_payment_hash = swap.payment_hash
|
||||
|
||||
if is_preview:
|
||||
self.window.show_transaction(tx, external_keypairs=external_keypairs, payment_identifier=payment_identifier)
|
||||
return
|
||||
@@ -711,6 +720,12 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
def broadcast_transaction(self, tx: Transaction, *, payment_identifier: PaymentIdentifier = None):
|
||||
# note: payment_identifier is explicitly passed as self.payto_e.payment_identifier might
|
||||
# already be cleared or otherwise have changed.
|
||||
if hasattr(tx, 'swap_payment_hash'):
|
||||
sm = self.wallet.lnworker.swap_manager
|
||||
swap = sm.get_swap(tx.swap_payment_hash)
|
||||
coro = sm.wait_for_htlcs_and_broadcast(swap, tx.swap_invoice, tx)
|
||||
self.window.run_coroutine_from_thread(coro, _('Awaiting lightning payment..'), on_result=self.window.on_swap_result)
|
||||
return
|
||||
|
||||
def broadcast_thread():
|
||||
# non-GUI thread
|
||||
|
||||
@@ -5,7 +5,7 @@ from PyQt5.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates
|
||||
from electrum.lnutil import ln_dummy_address
|
||||
from electrum.bitcoin import get_dummy_address
|
||||
from electrum.transaction import PartialTxOutput, PartialTransaction
|
||||
|
||||
from electrum.gui import messages
|
||||
@@ -173,7 +173,7 @@ class SwapDialog(WindowModalDialog, QtEventListener):
|
||||
|
||||
def _spend_max_forward_swap(self, tx: Optional[PartialTransaction]) -> None:
|
||||
if tx:
|
||||
amount = tx.output_value_for_address(ln_dummy_address())
|
||||
amount = tx.output_value_for_address(get_dummy_address('swap'))
|
||||
self.send_amount_e.setAmount(amount)
|
||||
else:
|
||||
self.send_amount_e.setAmount(None)
|
||||
@@ -256,7 +256,7 @@ class SwapDialog(WindowModalDialog, QtEventListener):
|
||||
lightning_amount_sat=lightning_amount,
|
||||
expected_onchain_amount_sat=onchain_amount + self.swap_manager.get_claim_fee(),
|
||||
)
|
||||
self.window.run_coroutine_from_thread(coro, _('Swapping funds'), on_result=self.on_result)
|
||||
self.window.run_coroutine_from_thread(coro, _('Swapping funds'), on_result=self.window.on_swap_result)
|
||||
return True
|
||||
else:
|
||||
lightning_amount = self.recv_amount_e.get_amount()
|
||||
@@ -294,7 +294,7 @@ class SwapDialog(WindowModalDialog, QtEventListener):
|
||||
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)]
|
||||
outputs = [PartialTxOutput.from_address_and_value(get_dummy_address('swap'), onchain_amount)]
|
||||
try:
|
||||
tx = self.window.wallet.make_unsigned_transaction(
|
||||
coins=coins,
|
||||
@@ -325,16 +325,7 @@ class SwapDialog(WindowModalDialog, QtEventListener):
|
||||
tx=tx,
|
||||
channels=self.channels,
|
||||
)
|
||||
self.window.run_coroutine_from_thread(coro, _('Swapping funds'), on_result=self.on_result)
|
||||
|
||||
def on_result(self, txid):
|
||||
msg = _("Submarine swap") + ': ' + (_("Success") if txid else _("Expired")) + '\n\n'
|
||||
if txid:
|
||||
msg += _("Funding transaction") + ': ' + txid + '\n'
|
||||
msg += _("Please remain online until the funding transaction is confirmed.")
|
||||
else:
|
||||
msg += _("Lightning funds were not received.")
|
||||
self.window.show_error_signal.emit(msg)
|
||||
self.window.run_coroutine_from_thread(coro, _('Swapping funds'), on_result=self.window.on_swap_result)
|
||||
|
||||
def get_description(self):
|
||||
onchain_funds = "onchain funds"
|
||||
|
||||
@@ -46,7 +46,7 @@ from electrum.simple_config import SimpleConfig
|
||||
from electrum.util import quantize_feerate
|
||||
from electrum import bitcoin
|
||||
|
||||
from electrum.bitcoin import base_encode, NLOCKTIME_BLOCKHEIGHT_MAX
|
||||
from electrum.bitcoin import base_encode, NLOCKTIME_BLOCKHEIGHT_MAX, get_dummy_address
|
||||
from electrum.i18n import _
|
||||
from electrum.plugin import run_hook
|
||||
from electrum import simple_config
|
||||
@@ -123,6 +123,8 @@ class TxInOutWidget(QWidget):
|
||||
legend=_("Change Address"), color=ColorScheme.YELLOW, tooltip=_("Wallet change address"))
|
||||
self.txo_color_2fa = TxOutputColoring(
|
||||
legend=_("TrustedCoin (2FA) batch fee"), color=ColorScheme.BLUE, tooltip=_("TrustedCoin (2FA) fee for the next batch of transactions"))
|
||||
self.txo_color_swap = TxOutputColoring(
|
||||
legend=_("Submarine swap address"), color=ColorScheme.BLUE, tooltip=_("Submarine swap address"))
|
||||
self.outputs_header = QLabel()
|
||||
self.outputs_textedit = QTextBrowserWithDefaultSize(750, 100)
|
||||
self.outputs_textedit.setOpenLinks(False) # disable automatic link opening
|
||||
@@ -139,6 +141,7 @@ class TxInOutWidget(QWidget):
|
||||
outheader_hbox.addWidget(self.txo_color_recv.legend_label)
|
||||
outheader_hbox.addWidget(self.txo_color_change.legend_label)
|
||||
outheader_hbox.addWidget(self.txo_color_2fa.legend_label)
|
||||
outheader_hbox.addWidget(self.txo_color_swap.legend_label)
|
||||
|
||||
vbox = QVBoxLayout()
|
||||
vbox.addLayout(self.inheader_hbox)
|
||||
@@ -164,9 +167,10 @@ class TxInOutWidget(QWidget):
|
||||
lnk.setToolTip(_('Click to open, right-click for menu'))
|
||||
lnk.setAnchor(True)
|
||||
lnk.setUnderlineStyle(QTextCharFormat.SingleUnderline)
|
||||
tf_used_recv, tf_used_change, tf_used_2fa = False, False, False
|
||||
tf_used_recv, tf_used_change, tf_used_2fa, tf_used_swap = False, False, False, False
|
||||
def addr_text_format(addr: str) -> QTextCharFormat:
|
||||
nonlocal tf_used_recv, tf_used_change, tf_used_2fa
|
||||
nonlocal tf_used_recv, tf_used_change, tf_used_2fa, tf_used_swap
|
||||
sm = self.wallet.lnworker.swap_manager
|
||||
if self.wallet.is_mine(addr):
|
||||
if self.wallet.is_change(addr):
|
||||
tf_used_change = True
|
||||
@@ -179,6 +183,9 @@ class TxInOutWidget(QWidget):
|
||||
fmt.setAnchor(True)
|
||||
fmt.setUnderlineStyle(QTextCharFormat.SingleUnderline)
|
||||
return fmt
|
||||
elif sm and sm.is_lockup_address_for_a_swap(addr) or addr==get_dummy_address('swap'):
|
||||
tf_used_swap = True
|
||||
return self.txo_color_swap.text_char_format
|
||||
elif self.wallet.is_billing_address(addr):
|
||||
tf_used_2fa = True
|
||||
return self.txo_color_2fa.text_char_format
|
||||
@@ -267,6 +274,7 @@ class TxInOutWidget(QWidget):
|
||||
self.txo_color_recv.legend_label.setVisible(tf_used_recv)
|
||||
self.txo_color_change.legend_label.setVisible(tf_used_change)
|
||||
self.txo_color_2fa.legend_label.setVisible(tf_used_2fa)
|
||||
self.txo_color_swap.legend_label.setVisible(tf_used_swap)
|
||||
|
||||
def _open_internal_link(self, target):
|
||||
"""Accepts either a str txid, str address, or a QUrl which should be
|
||||
|
||||
Reference in New Issue
Block a user