Skip to content

PSBT nostr, send invoice/tx description along with PSBT #9793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions electrum/gui/qml/components/ExportTxDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ElDialog {
// if text_qr is undefined text will be used
property string text_help
property string text_warn
property string tx_label

title: qsTr('Share Transaction')

Expand Down
3 changes: 2 additions & 1 deletion electrum/gui/qml/components/WalletMainView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ Item {
? ''
: [qsTr('Warning: Some data (prev txs / "full utxos") was left out of the QR code as it would not fit.'),
qsTr('This might cause issues if signing offline.'),
qsTr('As a workaround, copy to clipboard or use the Share option instead.')].join(' ')
qsTr('As a workaround, copy to clipboard or use the Share option instead.')].join(' '),
tx_label: data[3]
})
dialog.open()
}
Expand Down
11 changes: 7 additions & 4 deletions electrum/gui/qml/qetxdetails.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,9 +383,11 @@ def update(self, from_txid: bool = False):

self.detailsChanged.emit()

if self._label != txinfo.label:
self._label = txinfo.label
self.labelChanged.emit()
if self._txid:
label = self._wallet.wallet.get_label_for_txid(self._txid)
if self._label != label:
self._label = label
self.labelChanged.emit()

def update_mined_status(self, tx_mined_info: TxMinedInfo):
self._mempool_depth = ''
Expand Down Expand Up @@ -505,4 +507,5 @@ def save(self):
@pyqtSlot(result='QVariantList')
def getSerializedTx(self):
txqr = self._tx.to_qr_data()
return [str(self._tx), txqr[0], txqr[1]]
label = self._wallet.wallet.get_label_for_txid(self._tx.txid())
return [str(self._tx), txqr[0], txqr[1], label]
3 changes: 2 additions & 1 deletion electrum/gui/qml/qetxfinalizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,8 @@ def on_sign_failed(self, msg: str = None):
@pyqtSlot(result='QVariantList')
def getSerializedTx(self):
txqr = self._tx.to_qr_data()
return [str(self._tx), txqr[0], txqr[1]]
label = self._wallet.wallet.get_label_for_txid(self._tx.txid())
return [str(self._tx), txqr[0], txqr[1], label]


class TxMonMixin(QtEventListener):
Expand Down
16 changes: 8 additions & 8 deletions electrum/gui/qt/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,15 +1165,15 @@ def show_transaction(
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,
):
show_transaction(
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,
)
Expand Down Expand Up @@ -1409,18 +1409,18 @@ def get_manually_selected_coins(self) -> Optional[Sequence[PartialTxInput]]:
"""
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(
Expand Down
37 changes: 17 additions & 20 deletions electrum/gui/qt/send_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,6 @@ def pay_onchain_dialog(
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:
Expand Down Expand Up @@ -353,12 +349,12 @@ def make_tx(fee_policy, *, confirmed_only=False, base_tx=None):
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,
Expand Down Expand Up @@ -711,7 +707,7 @@ def pay_lightning_invoice(self, invoice: Invoice):
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
Expand All @@ -724,9 +720,7 @@ def pay_lightning_invoice(self, invoice: Invoice):
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)
Expand All @@ -741,7 +735,7 @@ def broadcast_transaction(self, tx: Transaction, *, payment_identifier: PaymentI

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))
Expand All @@ -750,19 +744,22 @@ def broadcast_thread():
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):
Expand Down
34 changes: 20 additions & 14 deletions electrum/gui/qt/transaction_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
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__)
Expand Down Expand Up @@ -409,7 +409,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,
Expand All @@ -420,7 +420,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:
Expand All @@ -445,7 +445,7 @@ def __init__(
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.
Expand All @@ -458,13 +458,15 @@ def __init__(
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]]
Expand All @@ -483,13 +485,8 @@ def __init__(
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)

Expand Down Expand Up @@ -570,6 +567,13 @@ def on_edited():
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
Expand Down Expand Up @@ -598,7 +602,7 @@ def do_broadcast(self):
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
Expand Down Expand Up @@ -713,6 +717,7 @@ def sign_done(success):
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)
Expand Down Expand Up @@ -842,7 +847,8 @@ def update(self):
# 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:
Expand Down
Loading