Kivy: Show fee dialog before opening a new channel.
Remove fee and rbf from settings, as they are now always proposed
This commit is contained in:
@@ -97,11 +97,12 @@ Builder.load_string('''
|
||||
on_release:
|
||||
popup.dismiss()
|
||||
Button:
|
||||
id: ok_button
|
||||
text: _('OK')
|
||||
size_hint: 0.5, None
|
||||
height: '48dp'
|
||||
on_release:
|
||||
root.pay()
|
||||
root.on_pay(root.tx)
|
||||
popup.dismiss()
|
||||
''')
|
||||
|
||||
@@ -110,33 +111,35 @@ Builder.load_string('''
|
||||
|
||||
class ConfirmTxDialog(FeeSliderDialog, Factory.Popup):
|
||||
|
||||
def __init__(self, app: 'ElectrumWindow', invoice):
|
||||
def __init__(self, app: 'ElectrumWindow', amount, make_tx, on_pay, *, show_final=True):
|
||||
|
||||
Factory.Popup.__init__(self)
|
||||
FeeSliderDialog.__init__(self, app.electrum_config, self.ids.slider)
|
||||
self.app = app
|
||||
self.show_final = bool(self.config.get('use_rbf'))
|
||||
self.invoice = invoice
|
||||
self.amount = amount
|
||||
self.make_tx = make_tx
|
||||
self.on_pay = on_pay
|
||||
self.show_final = show_final
|
||||
self.update_slider()
|
||||
self.update_text()
|
||||
self.update_tx()
|
||||
|
||||
def update_tx(self):
|
||||
outputs = self.invoice.outputs
|
||||
rbf = not bool(self.ids.final_cb.active) if self.show_final else False
|
||||
try:
|
||||
# make unsigned transaction
|
||||
coins = self.app.wallet.get_spendable_coins(None)
|
||||
tx = self.app.wallet.make_unsigned_transaction(coins=coins, outputs=outputs)
|
||||
tx = self.make_tx(rbf)
|
||||
except NotEnoughFunds:
|
||||
self.warning = _("Not enough funds")
|
||||
self.ids.ok_button.disabled = True
|
||||
return
|
||||
except Exception as e:
|
||||
self.logger.exception('')
|
||||
self.ids.ok_button.disabled = True
|
||||
self.app.logger.exception('')
|
||||
self.app.show_error(repr(e))
|
||||
return
|
||||
rbf = not bool(self.ids.final_cb.active) if self.show_final else False
|
||||
tx.set_rbf(rbf)
|
||||
amount = sum(map(lambda x: x.value, outputs)) if '!' not in [x.value for x in outputs] else tx.output_value()
|
||||
self.ids.ok_button.disabled = False
|
||||
amount = self.amount if self.amount != '!' else tx.output_value()
|
||||
tx_size = tx.estimated_size()
|
||||
fee = tx.get_fee()
|
||||
feerate = Decimal(fee) / tx_size # sat/byte
|
||||
@@ -166,9 +169,6 @@ class ConfirmTxDialog(FeeSliderDialog, Factory.Popup):
|
||||
target, tooltip, dyn = self.config.get_fee_target()
|
||||
self.ids.fee_button.text = target
|
||||
|
||||
def pay(self):
|
||||
self.app.protected(_('Send payment?'), self.app.send_screen.send_tx, (self.tx, self.invoice))
|
||||
|
||||
def on_fee_button(self):
|
||||
fee_dialog = FeeDialog(self, self.config, self.after_fee_changed)
|
||||
fee_dialog.open()
|
||||
|
||||
@@ -12,6 +12,7 @@ from electrum.logging import Logger
|
||||
from electrum.lnutil import ln_dummy_address
|
||||
|
||||
from .label_dialog import LabelDialog
|
||||
from .confirm_tx_dialog import ConfirmTxDialog
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...main_window import ElectrumWindow
|
||||
@@ -174,20 +175,26 @@ class LightningOpenChannelDialog(Factory.Popup, Logger):
|
||||
else:
|
||||
conn_str = str(self.trampolines[self.pubkey])
|
||||
amount = '!' if self.is_max else self.app.get_amount(self.amount)
|
||||
self.app.protected('Create a new channel?', self.do_open_channel, (conn_str, amount))
|
||||
self.dismiss()
|
||||
|
||||
def do_open_channel(self, conn_str, amount, password):
|
||||
coins = self.app.wallet.get_spendable_coins(None, nonlocal_only=True)
|
||||
lnworker = self.app.wallet.lnworker
|
||||
try:
|
||||
funding_tx = lnworker.mktx_for_open_channel(coins=coins, funding_sat=amount)
|
||||
except Exception as e:
|
||||
self.logger.exception("Problem opening channel")
|
||||
self.app.show_error(_('Problem opening channel: ') + '\n' + repr(e))
|
||||
return
|
||||
coins = self.app.wallet.get_spendable_coins(None, nonlocal_only=True)
|
||||
make_tx = lambda rbf: lnworker.mktx_for_open_channel(
|
||||
coins=coins,
|
||||
funding_sat=amount,
|
||||
fee_est=None)
|
||||
on_pay = lambda tx: self.app.protected('Create a new channel?', self.do_open_channel, (tx, conn_str))
|
||||
d = ConfirmTxDialog(
|
||||
self.app,
|
||||
amount = amount,
|
||||
make_tx=make_tx,
|
||||
on_pay=on_pay,
|
||||
show_final=False)
|
||||
d.open()
|
||||
|
||||
def do_open_channel(self, funding_tx, conn_str, password):
|
||||
# read funding_sat from tx; converts '!' to int value
|
||||
funding_sat = funding_tx.output_value_for_address(ln_dummy_address())
|
||||
lnworker = self.app.wallet.lnworker
|
||||
try:
|
||||
chan, funding_tx = lnworker.open_channel(
|
||||
connect_str=conn_str,
|
||||
@@ -196,7 +203,7 @@ class LightningOpenChannelDialog(Factory.Popup, Logger):
|
||||
push_amt_sat=0,
|
||||
password=password)
|
||||
except Exception as e:
|
||||
self.logger.exception("Problem opening channel")
|
||||
self.app.logger.exception("Problem opening channel")
|
||||
self.app.show_error(_('Problem opening channel: ') + '\n' + repr(e))
|
||||
return
|
||||
n = chan.constraints.funding_txn_minimum_depth
|
||||
|
||||
@@ -49,11 +49,6 @@ Builder.load_string('''
|
||||
description: _("Base unit for Bitcoin amounts.")
|
||||
action: partial(root.unit_dialog, self)
|
||||
CardSeparator
|
||||
SettingsItem:
|
||||
title: _('Onchain fees') + ': ' + app.fee_status
|
||||
description: _('Choose how transaction fees are estimated')
|
||||
action: lambda dt: app.fee_dialog()
|
||||
CardSeparator
|
||||
SettingsItem:
|
||||
status: root.fx_status()
|
||||
title: _('Fiat Currency') + ': ' + self.status
|
||||
@@ -66,16 +61,6 @@ Builder.load_string('''
|
||||
description: _("Save and synchronize your labels.")
|
||||
action: partial(root.plugin_dialog, 'labels', self)
|
||||
CardSeparator
|
||||
SettingsItem:
|
||||
status: 'ON' if app.use_rbf else 'OFF'
|
||||
title: _('Replace-by-fee') + ': ' + self.status
|
||||
description: _("Create replaceable transactions.")
|
||||
message:
|
||||
_('If you check this box, your transactions will be marked as non-final,') \
|
||||
+ ' ' + _('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pays higher fees.') \
|
||||
+ ' ' + _('Note that some merchants do not accept non-final transactions until they are confirmed.')
|
||||
action: partial(root.boolean_dialog, 'use_rbf', _('Replace by fee'), self.message)
|
||||
CardSeparator
|
||||
SettingsItem:
|
||||
status: _('Yes') if app.use_unconfirmed else _('No')
|
||||
title: _('Spend unconfirmed') + ': ' + self.status
|
||||
|
||||
@@ -36,7 +36,7 @@ from electrum.lnutil import RECEIVED, SENT, PaymentFailure
|
||||
from electrum.logging import Logger
|
||||
|
||||
from .dialogs.question import Question
|
||||
from .dialogs.lightning_open_channel import LightningOpenChannelDialog
|
||||
from .dialogs.confirm_tx_dialog import ConfirmTxDialog
|
||||
|
||||
from electrum.gui.kivy import KIVY_GUI_PATH
|
||||
from electrum.gui.kivy.i18n import _
|
||||
@@ -372,8 +372,12 @@ class SendScreen(CScreen, Logger):
|
||||
threading.Thread(target=pay_thread).start()
|
||||
|
||||
def _do_pay_onchain(self, invoice: OnchainInvoice) -> None:
|
||||
from .dialogs.confirm_tx_dialog import ConfirmTxDialog
|
||||
d = ConfirmTxDialog(self.app, invoice)
|
||||
outputs = invoice.outputs
|
||||
amount = sum(map(lambda x: x.value, outputs)) if '!' not in [x.value for x in outputs] else '!'
|
||||
coins = self.app.wallet.get_spendable_coins(None)
|
||||
make_tx = lambda rbf: self.app.wallet.make_unsigned_transaction(coins=coins, outputs=outputs, rbf=rbf)
|
||||
on_pay = lambda tx: self.app.protected(_('Send payment?'), self.send_tx, (tx, invoice))
|
||||
d = ConfirmTxDialog(self.app, amount=amount, make_tx=make_tx, on_pay=on_pay)
|
||||
d.open()
|
||||
|
||||
def send_tx(self, tx, invoice, password):
|
||||
|
||||
@@ -1796,9 +1796,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||
|
||||
def mktx_for_open_channel(self, funding_sat):
|
||||
coins = self.get_coins(nonlocal_only=True)
|
||||
make_tx = lambda fee_est: self.wallet.lnworker.mktx_for_open_channel(coins=coins,
|
||||
funding_sat=funding_sat,
|
||||
fee_est=fee_est)
|
||||
make_tx = lambda fee_est: self.wallet.lnworker.mktx_for_open_channel(
|
||||
coins=coins,
|
||||
funding_sat=funding_sat,
|
||||
fee_est=fee_est)
|
||||
return make_tx
|
||||
|
||||
def open_channel(self, connect_str, funding_sat, push_amt):
|
||||
@@ -1821,11 +1822,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||
# read funding_sat from tx; converts '!' to int value
|
||||
funding_sat = funding_tx.output_value_for_address(ln_dummy_address())
|
||||
def task():
|
||||
return self.wallet.lnworker.open_channel(connect_str=connect_str,
|
||||
funding_tx=funding_tx,
|
||||
funding_sat=funding_sat,
|
||||
push_amt_sat=push_amt,
|
||||
password=password)
|
||||
return self.wallet.lnworker.open_channel(
|
||||
connect_str=connect_str,
|
||||
funding_tx=funding_tx,
|
||||
funding_sat=funding_sat,
|
||||
push_amt_sat=push_amt,
|
||||
password=password)
|
||||
def on_success(args):
|
||||
chan, funding_tx = args
|
||||
n = chan.constraints.funding_txn_minimum_depth
|
||||
|
||||
@@ -183,8 +183,8 @@ async def sweep(
|
||||
fee: int = None,
|
||||
imax=100,
|
||||
locktime=None,
|
||||
tx_version=None
|
||||
) -> PartialTransaction:
|
||||
tx_version=None) -> PartialTransaction:
|
||||
|
||||
inputs, keypairs = await sweep_preparations(privkeys, network, imax)
|
||||
total = sum(txin.value_sats() for txin in inputs)
|
||||
if fee is None:
|
||||
@@ -1236,9 +1236,14 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
assert is_address(selected_addr), f"not valid bitcoin address: {selected_addr}"
|
||||
return selected_addr
|
||||
|
||||
def make_unsigned_transaction(self, *, coins: Sequence[PartialTxInput],
|
||||
outputs: List[PartialTxOutput], fee=None,
|
||||
change_addr: str = None, is_sweep=False) -> PartialTransaction:
|
||||
def make_unsigned_transaction(
|
||||
self, *,
|
||||
coins: Sequence[PartialTxInput],
|
||||
outputs: List[PartialTxOutput],
|
||||
fee=None,
|
||||
change_addr: str = None,
|
||||
is_sweep=False,
|
||||
rbf=False) -> PartialTransaction:
|
||||
|
||||
if any([c.already_has_some_signatures() for c in coins]):
|
||||
raise Exception("Some inputs already contain signatures!")
|
||||
@@ -1298,12 +1303,13 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
old_change_addrs = []
|
||||
# change address. if empty, coin_chooser will set it
|
||||
change_addrs = self.get_change_addresses_for_new_transaction(change_addr or old_change_addrs)
|
||||
tx = coin_chooser.make_tx(coins=coins,
|
||||
inputs=txi,
|
||||
outputs=list(outputs) + txo,
|
||||
change_addrs=change_addrs,
|
||||
fee_estimator_vb=fee_estimator,
|
||||
dust_threshold=self.dust_threshold())
|
||||
tx = coin_chooser.make_tx(
|
||||
coins=coins,
|
||||
inputs=txi,
|
||||
outputs=list(outputs) + txo,
|
||||
change_addrs=change_addrs,
|
||||
fee_estimator_vb=fee_estimator,
|
||||
dust_threshold=self.dust_threshold())
|
||||
else:
|
||||
# "spend max" branch
|
||||
# note: This *will* spend inputs with negative effective value (if there are any).
|
||||
@@ -1325,7 +1331,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
# Timelock tx to current height.
|
||||
tx.locktime = get_locktime_for_new_transaction(self.network)
|
||||
|
||||
tx.set_rbf(False) # caller can set RBF manually later
|
||||
tx.set_rbf(rbf)
|
||||
tx.add_info_from_wallet(self)
|
||||
run_hook('make_unsigned_transaction', self, tx)
|
||||
return tx
|
||||
@@ -1340,8 +1346,8 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
coins=coins,
|
||||
outputs=outputs,
|
||||
fee=fee,
|
||||
change_addr=change_addr)
|
||||
tx.set_rbf(rbf)
|
||||
change_addr=change_addr,
|
||||
rbf=rbf)
|
||||
if tx_version is not None:
|
||||
tx.version = tx_version
|
||||
if sign:
|
||||
|
||||
Reference in New Issue
Block a user