diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index edf9cba3d..e70b0da20 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -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( diff --git a/electrum/gui/qt/send_tab.py b/electrum/gui/qt/send_tab.py index 583749525..2817784bf 100644 --- a/electrum/gui/qt/send_tab.py +++ b/electrum/gui/qt/send_tab.py @@ -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): diff --git a/electrum/gui/qt/transaction_dialog.py b/electrum/gui/qt/transaction_dialog.py index dfbfc6684..79312087d 100644 --- a/electrum/gui/qt/transaction_dialog.py +++ b/electrum/gui/qt/transaction_dialog.py @@ -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: