@@ -485,7 +485,9 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
485485 assert (m_current_transaction);
486486
487487 const QString confirmation = tr (" Confirm send coins" );
488- auto confirmationDialog = new SendConfirmationDialog (confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, !model->wallet ().privateKeysDisabled (), model->getOptionsModel ()->getEnablePSBTControls (), this );
488+ const bool enable_send{!model->wallet ().privateKeysDisabled () || model->wallet ().hasExternalSigner ()};
489+ const bool always_show_unsigned{model->getOptionsModel ()->getEnablePSBTControls ()};
490+ auto confirmationDialog = new SendConfirmationDialog (confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, enable_send, always_show_unsigned, this );
489491 confirmationDialog->setAttribute (Qt::WA_DeleteOnClose);
490492 // TODO: Replace QDialog::exec() with safer QDialog::show().
491493 const auto retval = static_cast <QMessageBox::StandardButton>(confirmationDialog->exec ());
@@ -498,23 +500,50 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
498500
499501 bool send_failure = false ;
500502 if (retval == QMessageBox::Save) {
503+ // "Create Unsigned" clicked
501504 CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx ())};
502505 PartiallySignedTransaction psbtx (mtx);
503506 bool complete = false ;
504- // Always fill without signing first. This prevents an external signer
505- // from being called prematurely and is not expensive.
506- TransactionError err = model->wallet ().fillPSBT (SIGHASH_ALL, false /* sign */ , true /* bip32derivs */ , nullptr , psbtx, complete);
507+ // Fill without signing
508+ TransactionError err = model->wallet ().fillPSBT (SIGHASH_ALL, /* sign=*/ false , /* bip32derivs=*/ true , /* n_signed=*/ nullptr , psbtx, complete);
507509 assert (!complete);
508510 assert (err == TransactionError::OK);
511+
512+ // Copy PSBT to clipboard and offer to save
513+ presentPSBT (psbtx);
514+ } else {
515+ // "Send" clicked
516+ assert (!model->wallet ().privateKeysDisabled () || model->wallet ().hasExternalSigner ());
517+ bool broadcast = true ;
509518 if (model->wallet ().hasExternalSigner ()) {
519+ CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx ())};
520+ PartiallySignedTransaction psbtx (mtx);
521+ bool complete = false ;
522+ // Always fill without signing first. This prevents an external signer
523+ // from being called prematurely and is not expensive.
524+ TransactionError err = model->wallet ().fillPSBT (SIGHASH_ALL, /* sign=*/ false , /* bip32derivs=*/ true , /* n_signed=*/ nullptr , psbtx, complete);
525+ assert (!complete);
526+ assert (err == TransactionError::OK);
510527 send_failure = !signWithExternalSigner (psbtx, mtx, complete);
528+ // Don't broadcast when user rejects it on the device or there's a failure:
529+ broadcast = complete && !send_failure;
530+ if (!send_failure) {
531+ // A transaction signed with an external signer is not always complete,
532+ // e.g. in a multisig wallet.
533+ if (complete) {
534+ // Prepare transaction for broadcast transaction if complete
535+ const CTransactionRef tx = MakeTransactionRef (mtx);
536+ m_current_transaction->setWtx (tx);
537+ } else {
538+ presentPSBT (psbtx);
539+ }
540+ }
511541 }
512542
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);
543+ // Broadcast the transaction, unless an external signer was used and it
544+ // failed, or more signatures are needed.
545+ if (broadcast) {
546+ // now send the prepared transaction
518547 WalletModel::SendCoinsReturn sendStatus = model->sendCoins (*m_current_transaction);
519548 // process sendStatus and on error generate message shown to user
520549 processSendCoinsReturn (sendStatus);
@@ -524,23 +553,6 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
524553 } else {
525554 send_failure = true ;
526555 }
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 ;
544556 }
545557 }
546558 if (!send_failure) {
0 commit comments