1
0

fix: psbt_nostr: don't allow to save tx without txid

Stops the psbt nostr plugin from trying to save transactions without
txid to the wallet history and doesn't give the user the option to do
so.
This commit is contained in:
f321x
2025-08-13 10:45:52 +02:00
parent 7346e9a37b
commit 478fb483e9
5 changed files with 27 additions and 15 deletions

View File

@@ -278,6 +278,7 @@ class CosignerWallet(Logger):
on_failure: Callable = None,
on_success: Callable = None
) -> None:
assert tx.txid(), "Shouldn't allow to save tx without txid"
try:
# TODO: adding tx should be handled more gracefully here:
# 1) don't replace tx with same tx with less signatures

View File

@@ -48,7 +48,7 @@ class QReceiveSignalObject(QObject):
QObject.__init__(self)
self._plugin = plugin
cosignerReceivedPsbt = pyqtSignal(str, str, str, str)
cosignerReceivedPsbt = pyqtSignal(str, str, str, str, bool)
sendPsbtFailed = pyqtSignal(str, arguments=['reason'])
sendPsbtSuccess = pyqtSignal()
@@ -138,7 +138,8 @@ class QmlCosignerWallet(EventListener, CosignerWallet):
def on_event_psbt_nostr_received(self, wallet, pubkey, event_id, tx: 'PartialTransaction', label: str):
if self.wallet == wallet:
self.tx = tx
self.plugin.so.cosignerReceivedPsbt.emit(pubkey, event_id, tx.serialize(), label)
can_be_saved = tx.txid() is not None
self.plugin.so.cosignerReceivedPsbt.emit(pubkey, event_id, tx.serialize(), label, can_be_saved)
def close(self):
super().close()
@@ -173,5 +174,5 @@ class QmlCosignerWallet(EventListener, CosignerWallet):
def reject_psbt(self, event_id):
self.mark_pending_event_rcvd(event_id)
def on_add_fail(self):
self.logger.error('failed to add tx to wallet')
def on_add_fail(self, error_msg: str):
self.logger.error(f'failed to add tx to wallet: {error_msg}')

View File

@@ -17,6 +17,7 @@ ElDialog {
}
property string tx_label
property bool can_be_saved
property int choice: PsbtReceiveDialog.Choice.None
// TODO: it might be better to defer popup until no dialogs are shown
@@ -81,6 +82,7 @@ ElDialog {
Layout.preferredWidth: 1
text: qsTr('Save to Wallet')
icon.source: Qt.resolvedUrl('../../../gui/icons/wallet.png')
visible: dialog.can_be_saved
onClicked: {
choice = PsbtReceiveDialog.Choice.Save
doAccept()

View File

@@ -7,9 +7,10 @@ import "../../../gui/qml/components/controls"
Item {
Connections {
target: AppController ? AppController.plugin('psbt_nostr') : null
function onCosignerReceivedPsbt(pubkey, event, tx, label) {
function onCosignerReceivedPsbt(pubkey, event, tx, label, can_be_saved) {
var dialog = psbtReceiveDialog.createObject(app, {
tx_label: label
tx_label: label,
can_be_saved: can_be_saved
})
dialog.accepted.connect(function () {
if (dialog.choice == PsbtReceiveDialog.Choice.Open) {

View File

@@ -102,7 +102,8 @@ class QtCosignerWallet(EventListener, CosignerWallet):
self.obj.cosignerReceivedPsbt.emit(*args) # put on UI thread via signal
def send_to_cosigners(self, tx: Union['Transaction', 'PartialTransaction'], label: str):
self.add_transaction_to_wallet(tx, label=label, on_failure=self.on_add_fail)
if tx.txid():
self.add_transaction_to_wallet(tx, label=label, on_failure=self.on_add_fail)
self.send_psbt(tx, label)
def do_send(self, messages: List[Tuple[str, dict]], txid: Optional[str] = None):
@@ -120,8 +121,10 @@ class QtCosignerWallet(EventListener, CosignerWallet):
except Exception as e:
self.window.show_error(str(e))
return
self.window.show_message(
_("Your transaction was sent to your cosigners via Nostr.") + '\n\n' + txid)
message = _("Your transaction was sent to your cosigners via Nostr.")
if txid:
message += '\n\n' + txid
self.window.show_message(message)
def on_receive(self, pubkey, event_id, tx, label):
msg = '<br/>'.join([
@@ -129,13 +132,17 @@ class QtCosignerWallet(EventListener, CosignerWallet):
_("A transaction was received from your cosigner with label: <br/><big>{}</big><br/>").format(label),
_("Do you want to open it now?")
])
result = self.window.show_message(msg, rich_text=True, icon=QMessageBox.Icon.Question, buttons=[
QMessageBox.StandardButton.Open,
(QPushButton('Discard'), QMessageBox.ButtonRole.DestructiveRole, 100),
(QPushButton('Save to wallet'), QMessageBox.ButtonRole.AcceptRole, 101)]
)
buttons = [
QMessageBox.StandardButton.Open,
(QPushButton('Discard'), QMessageBox.ButtonRole.DestructiveRole, 100),
]
if tx.txid(): # cannot add tx without txid to wallet history (e.g. unsigned legacy tx)
buttons.append(
(QPushButton('Save to wallet'), QMessageBox.ButtonRole.AcceptRole, 101) # type: ignore
)
result = self.window.show_message(msg, rich_text=True, icon=QMessageBox.Icon.Question, buttons=buttons)
if result == QMessageBox.StandardButton.Open:
if label:
if label and tx.txid():
self.wallet.set_label(tx.txid(), label)
show_transaction(tx, parent=self.window, prompt_if_unsaved=True, on_closed=partial(self.on_tx_dialog_closed, event_id))
else: