diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 3962dd08878..8ffd4533019 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -281,6 +281,8 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa } // prepare transaction for getting txFee earlier + // Create unsigned transaction to support creating unsigned PSBTs. + // Signing is deferred until the user clicks "Send". m_current_transaction = std::make_unique(recipients); WalletModel::SendCoinsReturn prepareStatus; @@ -288,7 +290,7 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa CCoinControl coin_control = *m_coin_control; coin_control.m_allow_other_inputs = !coin_control.HasSelected(); // future, could introduce a checkbox to customize this value. - prepareStatus = model->prepareTransaction(*m_current_transaction, coin_control); + prepareStatus = model->prepareTransaction(*m_current_transaction, coin_control, /*sign=*/false); // process prepareStatus and on error generate message shown to user processSendCoinsReturn(prepareStatus, @@ -540,6 +542,24 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) presentPSBT(psbtx); } } + } else { + // Sign the transaction now that the user has confirmed they want to send. + CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())}; + PartiallySignedTransaction psbtx(mtx); + bool complete = false; + // Fill and sign the PSBT + const auto err{model->wallet().fillPSBT(std::nullopt, /*sign=*/true, /*bip32derivs=*/false, /*n_signed=*/nullptr, psbtx, complete)}; + if (err || !complete) { + Q_EMIT message(tr("Send Coins"), tr("Failed to sign transaction."), + CClientUIInterface::MSG_ERROR); + send_failure = true; + broadcast = false; + } else { + // Extract the signed transaction + CHECK_NONFATAL(FinalizeAndExtractPSBT(psbtx, mtx)); + const CTransactionRef tx = MakeTransactionRef(mtx); + m_current_transaction->setWtx(tx); + } } // Broadcast the transaction, unless an external signer was used and it diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 694fb535b57..ec1829e5fc7 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -147,7 +147,7 @@ bool WalletModel::validateAddress(const QString& address) const return IsValidDestinationString(address.toStdString()); } -WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl) +WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl, bool sign) { CAmount total = 0; bool fSubtractFeeFromAmount = false; @@ -203,7 +203,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact int nChangePosRet = -1; auto& newTx = transaction.getWtx(); - const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired); + // Only sign if explicitly requested via the sign parameter. + const bool should_sign = sign && !wallet().privateKeysDisabled(); + const auto& res = m_wallet->createTransaction(vecSend, coinControl, should_sign, nChangePosRet, nFeeRequired); newTx = res ? *res : nullptr; transaction.setTransactionFee(nFeeRequired); if (fSubtractFeeFromAmount && newTx) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index ece797bfd9e..1743128dcf4 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -96,7 +96,7 @@ class WalletModel : public QObject }; // prepare transaction for getting txfee before sending coins - SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const wallet::CCoinControl& coinControl); + SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const wallet::CCoinControl& coinControl, bool sign = false); // Send coins to a list of recipients void sendCoins(WalletModelTransaction& transaction);