Skip to content

Commit 4ed2a3b

Browse files
committed
gui: restore Send for external signer
Before this change the send confirmation dialog would keep the Send option disabled. The Create Unsigned choice would actually send. This is potentially confusing. With this change the Create Unsigned button will not attempt to sign and always produce a PSBT. The Send button will attempt to sign, and only return a PSBT if more signatures are needed. When using an external signer, the Create Unsigned option only appears when PSBT controls are enabled in the wallet settings. Closes #551
1 parent e1c1c61 commit 4ed2a3b

File tree

2 files changed

+29
-25
lines changed

2 files changed

+29
-25
lines changed

src/qt/sendcoinsdialog.cpp

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
490490
assert(m_current_transaction);
491491

492492
const QString confirmation = tr("Confirm send coins");
493-
auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, !model->wallet().privateKeysDisabled(), model->getOptionsModel()->getEnablePSBTControls(), this);
493+
auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, /*enable_send=*/!model->wallet().privateKeysDisabled() || model->wallet().hasExternalSigner(), /*always_show_unsigned=*/model->getOptionsModel()->getEnablePSBTControls(), this);
494494
confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
495495
// TODO: Replace QDialog::exec() with safer QDialog::show().
496496
const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec());
@@ -502,19 +502,38 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
502502
}
503503

504504
bool send_failure = false;
505-
if (retval == QMessageBox::Save) {
505+
if (retval == QMessageBox::Save) { // Create Unsigned clicked
506506
CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())};
507507
PartiallySignedTransaction psbtx(mtx);
508-
bool complete = false;
508+
// Copy PSBT to clipboard and offer to save
509+
presentPSBT(psbtx);
510+
} else { // Send clicked
511+
assert(!model->wallet().privateKeysDisabled() || model->wallet().hasExternalSigner());
512+
bool broadcast = true;
509513
if (model->wallet().hasExternalSigner()) {
514+
CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())};
515+
PartiallySignedTransaction psbtx(mtx);
516+
bool complete = false;
510517
send_failure = !signWithExternalSigner(psbtx, mtx, complete);
518+
// Don't broadcast when user rejects it on the device or there's a failure:
519+
broadcast = complete && !send_failure;
520+
if (!send_failure) {
521+
// A transaction signed with an external signer is not always complete,
522+
// e.g. in a multisig wallet.
523+
if (complete) {
524+
// Prepare transaction for broadcast transaction if complete
525+
const CTransactionRef tx = MakeTransactionRef(mtx);
526+
m_current_transaction->setWtx(tx);
527+
} else {
528+
presentPSBT(psbtx);
529+
}
530+
}
511531
}
512532

513-
// Broadcast transaction if complete (even with an external signer this
514-
// is not always the case, e.g. in a multisig wallet).
515-
if (complete) {
516-
const CTransactionRef tx = MakeTransactionRef(mtx);
517-
m_current_transaction->setWtx(tx);
533+
// Broadcast the transaction, unless an external was used and it
534+
// failed, or more signatures are needed.
535+
if (broadcast) {
536+
// now send the prepared transaction
518537
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
519538
// process sendStatus and on error generate message shown to user
520539
processSendCoinsReturn(sendStatus);
@@ -524,23 +543,6 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
524543
} else {
525544
send_failure = true;
526545
}
527-
return;
528-
}
529-
530-
// Copy PSBT to clipboard and offer to save
531-
assert(!complete);
532-
presentPSBT(psbtx);
533-
} else {
534-
assert(!model->wallet().privateKeysDisabled());
535-
// now send the prepared transaction
536-
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
537-
// process sendStatus and on error generate message shown to user
538-
processSendCoinsReturn(sendStatus);
539-
540-
if (sendStatus.status == WalletModel::OK) {
541-
Q_EMIT coinsSent(m_current_transaction->getWtx()->GetHash());
542-
} else {
543-
send_failure = true;
544546
}
545547
}
546548
if (!send_failure) {

src/qt/sendcoinsdialog.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ class SendConfirmationDialog : public QMessageBox
128128

129129
public:
130130
SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, bool enable_send = true, bool always_show_unsigned = true, QWidget* parent = nullptr);
131+
/* Returns QMessageBox::Cancel, QMessageBox::Yes when send is
132+
clicked and QMessageBox::Save when Create Unsigned is clicked. */
131133
int exec() override;
132134

133135
private Q_SLOTS:

0 commit comments

Comments
 (0)