qt: pass Invoice object to transaction dialog when appropriate.
This is purely informational and optional, with the main immediate use to provide the invoice description/message/label to the transaction dialog, so it can be stored when saving the tx in history, or passed along with PSBTs sent to cosigners. Before, the tx description was not saved in history when an invoice was not saved before signing and saving the tx for sending later.
This commit is contained in:
@@ -1169,7 +1169,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
tx: Transaction,
|
||||
*,
|
||||
external_keypairs: Mapping[bytes, bytes] = None,
|
||||
payment_identifier: PaymentIdentifier = None,
|
||||
invoice: Invoice = None,
|
||||
show_sign_button: bool = True,
|
||||
show_broadcast_button: bool = True,
|
||||
):
|
||||
@@ -1177,7 +1177,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
tx,
|
||||
parent=self,
|
||||
external_keypairs=external_keypairs,
|
||||
payment_identifier=payment_identifier,
|
||||
invoice=invoice,
|
||||
show_sign_button=show_sign_button,
|
||||
show_broadcast_button=show_broadcast_button,
|
||||
)
|
||||
@@ -1413,18 +1413,18 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
"""
|
||||
return self.utxo_list.get_spend_list()
|
||||
|
||||
def broadcast_or_show(self, tx: Transaction, *, payment_identifier: PaymentIdentifier = None):
|
||||
def broadcast_or_show(self, tx: Transaction, *, invoice: 'Invoice' = None):
|
||||
if not tx.is_complete():
|
||||
self.show_transaction(tx, payment_identifier=payment_identifier)
|
||||
self.show_transaction(tx, invoice=invoice)
|
||||
return
|
||||
if not self.network:
|
||||
self.show_error(_("You can't broadcast a transaction without a live network connection."))
|
||||
self.show_transaction(tx, payment_identifier=payment_identifier)
|
||||
self.show_transaction(tx, invoice=invoice)
|
||||
return
|
||||
self.broadcast_transaction(tx, payment_identifier=payment_identifier)
|
||||
self.broadcast_transaction(tx, invoice=invoice)
|
||||
|
||||
def broadcast_transaction(self, tx: Transaction, *, payment_identifier: PaymentIdentifier = None):
|
||||
self.send_tab.broadcast_transaction(tx, payment_identifier=payment_identifier)
|
||||
def broadcast_transaction(self, tx: Transaction, *, invoice: Invoice = None):
|
||||
self.send_tab.broadcast_transaction(tx, invoice=invoice)
|
||||
|
||||
@protected
|
||||
def sign_tx(
|
||||
|
||||
@@ -305,10 +305,6 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
if run_hook('abort_send', self):
|
||||
return
|
||||
|
||||
payment_identifier = None
|
||||
if invoice and invoice.bip70:
|
||||
payment_identifier = payment_identifier_from_invoice(self.wallet, invoice)
|
||||
|
||||
is_sweep = bool(external_keypairs)
|
||||
# we call get_coins inside make_tx, so that inputs can be changed dynamically
|
||||
if get_coins is None:
|
||||
@@ -354,12 +350,12 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
tx.swap_payment_hash = swap.payment_hash
|
||||
|
||||
if is_preview:
|
||||
self.window.show_transaction(tx, external_keypairs=external_keypairs, payment_identifier=payment_identifier)
|
||||
self.window.show_transaction(tx, external_keypairs=external_keypairs, invoice=invoice)
|
||||
return
|
||||
self.save_pending_invoice()
|
||||
def sign_done(success):
|
||||
if success:
|
||||
self.window.broadcast_or_show(tx, payment_identifier=payment_identifier)
|
||||
self.window.broadcast_or_show(tx, invoice=invoice)
|
||||
self.window.sign_tx(
|
||||
tx,
|
||||
callback=sign_done,
|
||||
@@ -712,7 +708,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
chan, swap_recv_amount_sat = can_pay_with_swap
|
||||
self.window.run_swap_dialog(is_reverse=False, recv_amount_sat=swap_recv_amount_sat, channels=[chan])
|
||||
elif r == 'onchain':
|
||||
self.pay_onchain_dialog(invoice.get_outputs(), nonlocal_only=True)
|
||||
self.pay_onchain_dialog(invoice.get_outputs(), nonlocal_only=True, invoice=invoice)
|
||||
return
|
||||
|
||||
assert lnworker is not None
|
||||
@@ -725,9 +721,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
coro = lnworker.pay_invoice(invoice, amount_msat=amount_msat)
|
||||
self.window.run_coroutine_from_thread(coro, _('Sending payment'))
|
||||
|
||||
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.
|
||||
def broadcast_transaction(self, tx: Transaction, *, invoice: Invoice = None):
|
||||
if hasattr(tx, 'swap_payment_hash'):
|
||||
sm = self.wallet.lnworker.swap_manager
|
||||
swap = sm.get_swap(tx.swap_payment_hash)
|
||||
@@ -742,7 +736,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
|
||||
def broadcast_thread():
|
||||
# non-GUI thread
|
||||
if payment_identifier and payment_identifier.has_expired():
|
||||
if invoice and invoice.has_expired():
|
||||
return False, _("Invoice has expired")
|
||||
try:
|
||||
self.network.run_from_another_thread(self.network.broadcast_transaction(tx))
|
||||
@@ -751,19 +745,22 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
except BestEffortRequestFailed as e:
|
||||
return False, repr(e)
|
||||
# success
|
||||
txid = tx.txid()
|
||||
if payment_identifier and payment_identifier.need_merchant_notify():
|
||||
refund_address = self.wallet.get_receiving_address()
|
||||
payment_identifier.notify_merchant(
|
||||
tx=tx,
|
||||
refund_address=refund_address,
|
||||
on_finished=self.notify_merchant_done_signal.emit
|
||||
)
|
||||
return True, txid
|
||||
if invoice and invoice.bip70:
|
||||
payment_identifier = payment_identifier_from_invoice(invoice)
|
||||
# FIXME: this should move to backend
|
||||
if payment_identifier and payment_identifier.need_merchant_notify():
|
||||
refund_address = self.wallet.get_receiving_address()
|
||||
payment_identifier.notify_merchant(
|
||||
tx=tx,
|
||||
refund_address=refund_address,
|
||||
on_finished=self.notify_merchant_done_signal.emit
|
||||
)
|
||||
return True, tx.txid()
|
||||
|
||||
# Capture current TL window; override might be removed on return
|
||||
parent = self.window.top_level_window(lambda win: isinstance(win, MessageBoxMixin))
|
||||
|
||||
# FIXME: move to backend and let Abstract_Wallet set broadcasting state, not gui
|
||||
self.wallet.set_broadcasting(tx, broadcasting_status=PR_BROADCASTING)
|
||||
|
||||
def broadcast_done(result):
|
||||
|
||||
@@ -64,7 +64,7 @@ from .my_treeview import create_toolbar_with_menu, QMenuWithConfig
|
||||
if TYPE_CHECKING:
|
||||
from .main_window import ElectrumWindow
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
from electrum.payment_identifier import PaymentIdentifier
|
||||
from electrum.invoices import Invoice
|
||||
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
@@ -418,7 +418,7 @@ def show_transaction(
|
||||
parent: 'ElectrumWindow',
|
||||
prompt_if_unsaved: bool = False,
|
||||
external_keypairs: Mapping[bytes, bytes] = None,
|
||||
payment_identifier: 'PaymentIdentifier' = None,
|
||||
invoice: 'Invoice' = None,
|
||||
on_closed: Callable[[], None] = None,
|
||||
show_sign_button: bool = True,
|
||||
show_broadcast_button: bool = True,
|
||||
@@ -429,7 +429,7 @@ def show_transaction(
|
||||
parent=parent,
|
||||
prompt_if_unsaved=prompt_if_unsaved,
|
||||
external_keypairs=external_keypairs,
|
||||
payment_identifier=payment_identifier,
|
||||
invoice=invoice,
|
||||
on_closed=on_closed,
|
||||
)
|
||||
if not show_sign_button:
|
||||
@@ -454,7 +454,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
parent: 'ElectrumWindow',
|
||||
prompt_if_unsaved: bool,
|
||||
external_keypairs: Mapping[bytes, bytes] = None,
|
||||
payment_identifier: 'PaymentIdentifier' = None,
|
||||
invoice: 'Invoice' = None,
|
||||
on_closed: Callable[[], None] = None,
|
||||
):
|
||||
'''Transactions in the wallet will show their description.
|
||||
@@ -467,13 +467,15 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
self.main_window = parent
|
||||
self.config = parent.config
|
||||
self.wallet = parent.wallet
|
||||
self.payment_identifier = payment_identifier
|
||||
self.invoice = invoice
|
||||
self.prompt_if_unsaved = prompt_if_unsaved
|
||||
self.on_closed = on_closed
|
||||
self.saved = False
|
||||
self.desc = None
|
||||
if txid := tx.txid():
|
||||
self.desc = self.wallet.get_label_for_txid(txid) or None
|
||||
if not self.desc and self.invoice:
|
||||
self.desc = self.invoice.get_message()
|
||||
self.setMinimumWidth(640)
|
||||
|
||||
self.psbt_only_widgets = [] # type: List[Union[QWidget, QAction]]
|
||||
@@ -492,13 +494,8 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
self.tx_desc_label = QLabel(_("Description:"))
|
||||
vbox.addWidget(self.tx_desc_label)
|
||||
self.tx_desc = ButtonsLineEdit('')
|
||||
def on_edited():
|
||||
text = self.tx_desc.text()
|
||||
if self.wallet.set_label(txid, text):
|
||||
self.main_window.history_list.update()
|
||||
self.main_window.utxo_list.update()
|
||||
self.main_window.labels_changed_signal.emit()
|
||||
self.tx_desc.editingFinished.connect(on_edited)
|
||||
|
||||
self.tx_desc.editingFinished.connect(self.store_tx_label)
|
||||
self.tx_desc.addCopyButton()
|
||||
vbox.addWidget(self.tx_desc)
|
||||
|
||||
@@ -579,6 +576,13 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
self.update()
|
||||
self.set_title()
|
||||
|
||||
def store_tx_label(self):
|
||||
text = self.tx_desc.text()
|
||||
if self.wallet.set_label(self.tx.txid(), text):
|
||||
self.main_window.history_list.update()
|
||||
self.main_window.utxo_list.update()
|
||||
self.main_window.labels_changed_signal.emit()
|
||||
|
||||
def set_tx(self, tx: 'Transaction'):
|
||||
# Take a copy; it might get updated in the main window by
|
||||
# e.g. the FX plugin. If this happens during or after a long
|
||||
@@ -607,7 +611,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
self.main_window.push_top_level_window(self)
|
||||
self.main_window.send_tab.save_pending_invoice()
|
||||
try:
|
||||
self.main_window.broadcast_transaction(self.tx, payment_identifier=self.payment_identifier)
|
||||
self.main_window.broadcast_transaction(self.tx, invoice=self.invoice)
|
||||
finally:
|
||||
self.main_window.pop_top_level_window(self)
|
||||
self.saved = True
|
||||
@@ -722,6 +726,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
def save(self):
|
||||
self.main_window.push_top_level_window(self)
|
||||
if self.main_window.save_transaction_into_wallet(self.tx):
|
||||
self.store_tx_label()
|
||||
self.save_button.setDisabled(True)
|
||||
self.saved = True
|
||||
self.main_window.pop_top_level_window(self)
|
||||
@@ -851,7 +856,8 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
# note: when not finalized, RBF and locktime changes do not trigger
|
||||
# a make_tx, so the txid is unreliable, hence:
|
||||
self.tx_hash_e.setText(_('Unknown'))
|
||||
if not self.wallet.adb.get_transaction(txid):
|
||||
tx_in_db = bool(self.wallet.adb.get_transaction(txid))
|
||||
if not desc and not tx_in_db:
|
||||
self.tx_desc.hide()
|
||||
self.tx_desc_label.hide()
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user