@@ -485,7 +485,9 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
485
485
assert (m_current_transaction);
486
486
487
487
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 );
489
491
confirmationDialog->setAttribute (Qt::WA_DeleteOnClose);
490
492
// TODO: Replace QDialog::exec() with safer QDialog::show().
491
493
const auto retval = static_cast <QMessageBox::StandardButton>(confirmationDialog->exec ());
@@ -498,23 +500,50 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
498
500
499
501
bool send_failure = false ;
500
502
if (retval == QMessageBox::Save) {
503
+ // "Create Unsigned" clicked
501
504
CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx ())};
502
505
PartiallySignedTransaction psbtx (mtx);
503
506
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);
507
509
assert (!complete);
508
510
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 ;
509
518
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);
510
527
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
+ }
511
541
}
512
542
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
518
547
WalletModel::SendCoinsReturn sendStatus = model->sendCoins (*m_current_transaction);
519
548
// process sendStatus and on error generate message shown to user
520
549
processSendCoinsReturn (sendStatus);
@@ -524,23 +553,6 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
524
553
} else {
525
554
send_failure = true ;
526
555
}
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 ;
544
556
}
545
557
}
546
558
if (!send_failure) {
0 commit comments