@@ -272,23 +272,18 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
272272 }
273273
274274 fNewRecipientAllowed = false ;
275- WalletModel::UnlockContext ctx (model->requestUnlock ());
276- if (!ctx.isValid ())
277- {
278- // Unlock wallet was cancelled
279- fNewRecipientAllowed = true ;
280- return false ;
281- }
282275
283276 // prepare transaction for getting txFee earlier
277+ // Create unsigned transaction to support creating unsigned PSBTs.
278+ // Signing is deferred until the user clicks "Send".
284279 m_current_transaction = std::make_unique<WalletModelTransaction>(recipients);
285280 WalletModel::SendCoinsReturn prepareStatus;
286281
287282 updateCoinControlState ();
288283
289284 CCoinControl coin_control = *m_coin_control;
290285 coin_control.m_allow_other_inputs = !coin_control.HasSelected (); // future, could introduce a checkbox to customize this value.
291- prepareStatus = model->prepareTransaction (*m_current_transaction, coin_control);
286+ prepareStatus = model->prepareTransaction (*m_current_transaction, coin_control, /* sign= */ false );
292287
293288 // process prepareStatus and on error generate message shown to user
294289 processSendCoinsReturn (prepareStatus,
@@ -357,7 +352,7 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
357352
358353 // append transaction size
359354 // : When reviewing a newly created PSBT (via Send flow), the transaction fee is shown, with "virtual size" of the transaction displayed for context
360- question_string.append (" (" + tr (" %1 kvB" , " PSBT transaction creation" ).arg ((double )m_current_transaction->getTransactionSize () / 1000 , 0 , ' g' , 3 ) + " ): " );
355+ question_string.append (" (" + tr (" %1 kvB (unsigned) " , " PSBT transaction creation" ).arg ((double )m_current_transaction->getTransactionSize () / 1000 , 0 , ' g' , 3 ) + " ): " );
361356
362357 // append transaction fee value
363358 question_string.append (" <span style='color:#aa0000; font-weight:bold;'>" );
@@ -515,6 +510,12 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
515510 presentPSBT (psbtx);
516511 } else {
517512 // "Send" clicked
513+ WalletModel::UnlockContext ctx (model->requestUnlock ());
514+ if (!ctx.isValid ()) {
515+ fNewRecipientAllowed = true ;
516+ return ;
517+ }
518+
518519 assert (!model->wallet ().privateKeysDisabled () || model->wallet ().hasExternalSigner ());
519520 bool broadcast = true ;
520521 if (model->wallet ().hasExternalSigner ()) {
@@ -540,6 +541,24 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
540541 presentPSBT (psbtx);
541542 }
542543 }
544+ } else {
545+ // Sign the transaction now that the user has confirmed they want to send.
546+ CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx ())};
547+ PartiallySignedTransaction psbtx (mtx);
548+ bool complete = false ;
549+ // Fill and sign the PSBT
550+ const auto err{model->wallet ().fillPSBT (std::nullopt , /* sign=*/ true , /* bip32derivs=*/ false , /* n_signed=*/ nullptr , psbtx, complete)};
551+ if (err || !complete) {
552+ Q_EMIT message (tr (" Send Coins" ), tr (" Failed to sign transaction." ),
553+ CClientUIInterface::MSG_ERROR );
554+ send_failure = true ;
555+ broadcast = false ;
556+ } else {
557+ // Extract the signed transaction
558+ CHECK_NONFATAL (FinalizeAndExtractPSBT (psbtx, mtx));
559+ const CTransactionRef tx = MakeTransactionRef (mtx);
560+ m_current_transaction->setWtx (tx);
561+ }
543562 }
544563
545564 // Broadcast the transaction, unless an external signer was used and it
0 commit comments