1
0

gui: detect if reserve inputs have been removed from tx

Adapts the gui(s) to detect if an existing reserve input has not been
used as input for the transaction even though the user tried to spend
max. This allows to show the lightning reserve warning not only for
reserve change outputs but also for existing reserve inputs that have
been ignored for this max spend transaction.
Still keeps the `is_utxo_reserve` flag on `PartialTxOutput` as it is
used in the qml gui.
This commit is contained in:
f321x
2025-07-29 14:36:55 +02:00
parent ead2c7c8de
commit 30b146033d
3 changed files with 18 additions and 2 deletions

View File

@@ -434,7 +434,10 @@ class QETxFinalizer(TxFeeSlider):
self.update_fee_warning_from_tx(tx=tx, invoice_amt=amount)
if self._amount.isMax and not self.warning:
if reserve_sats := sum(txo.value for txo in tx.outputs() if txo.is_utxo_reserve):
if reserve_sats := self._wallet.wallet.tx_keeps_ln_utxo_reserve(
tx,
gui_spend_max=self._amount.isMax
):
reserve_str = self._config.format_amount_and_units(reserve_sats)
self.warning = ' '.join([
_('Warning') + ':',

View File

@@ -544,7 +544,7 @@ class TxEditor(WindowModalDialog):
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.'))
# warn if a reserve utxo was added
if reserve_sats := sum(txo.value for txo in self.tx.outputs() if txo.is_utxo_reserve):
if reserve_sats := self.wallet.tx_keeps_ln_utxo_reserve(self.tx, gui_spend_max=bool(self.output_value == '!')):
reserve_str = self.main_window.config.format_amount_and_units(reserve_sats)
messages.append(_('Could not spend max: a security reserve of {} was kept for your Lightning channels.').format(reserve_str))
# warn if we merge from mempool

View File

@@ -1911,6 +1911,19 @@ class Abstract_Wallet(ABC, Logger, EventListener):
def is_low_reserve(self) -> bool:
return self.should_keep_reserve_utxo([], [], False)
def tx_keeps_ln_utxo_reserve(self, tx, *, gui_spend_max: bool) -> Optional[int]:
if reserve_output_amount := sum(txo.value for txo in tx.outputs() if txo.is_utxo_reserve):
# tx has a reserve change output
return reserve_output_amount
if gui_spend_max: # user tried to spend max amount
coins_in_wallet = self.get_spendable_coins(nonlocal_only=False, confirmed_only=False)
amount_in_wallet = sum(c.value_sats() for c in coins_in_wallet)
tx_spend_amount = tx.output_value() + tx.get_fee()
if amount_in_wallet - tx_spend_amount == self.config.LN_UTXO_RESERVE:
# tx keeps exactly LN_UTXO_RESERVE amount sats in the wallet
return self.config.LN_UTXO_RESERVE
return None
@profiler(min_threshold=0.1)
def make_unsigned_transaction(
self, *,