1
0

Merge pull request #9793 from accumulator/psbt_nostr_send_description

PSBT nostr, send invoice/tx description along with PSBT
This commit is contained in:
ThomasV
2025-05-15 09:44:55 +02:00
committed by GitHub
11 changed files with 133 additions and 90 deletions

View File

@@ -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(

View File

@@ -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):

View File

@@ -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: