diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -63,6 +63,7 @@ Ui::SendCoinsDialog *ui; ClientModel *clientModel; WalletModel *model; + std::unique_ptr m_current_transaction; bool fNewRecipientAllowed; bool fFeeMinimized; const PlatformStyle *platformStyle; @@ -74,6 +75,9 @@ processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString()); void minimizeFeeSection(bool fMinimize); + // Format confirmation message + bool PrepareSendText(QString &question_string, QString &informative_text, + QString &detailed_text); void updateFeeMinimizedLabel(); // Update the passed in CCoinControl with state from the GUI void updateCoinControlState(CCoinControl &ctrl); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -241,11 +241,9 @@ delete ui; } -void SendCoinsDialog::on_sendButton_clicked() { - if (!model || !model->getOptionsModel()) { - return; - } - +bool SendCoinsDialog::PrepareSendText(QString &question_string, + QString &informative_text, + QString &detailed_text) { QList recipients; bool valid = true; @@ -263,7 +261,7 @@ } if (!valid || recipients.isEmpty()) { - return; + return false; } fNewRecipientAllowed = false; @@ -271,11 +269,12 @@ if (!ctx.isValid()) { // Unlock wallet was cancelled fNewRecipientAllowed = true; - return; + return false; } // prepare transaction for getting txFee earlier - WalletModelTransaction currentTransaction(recipients); + m_current_transaction = + std::make_unique(recipients); WalletModel::SendCoinsReturn prepareStatus; // Always use a CCoinControl instance, use the CoinControlDialog instance if @@ -287,24 +286,23 @@ updateCoinControlState(ctrl); - prepareStatus = model->prepareTransaction(currentTransaction, ctrl); + prepareStatus = model->prepareTransaction(*m_current_transaction, ctrl); // process prepareStatus and on error generate message shown to user - processSendCoinsReturn( - prepareStatus, - BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), - currentTransaction.getTransactionFee())); + processSendCoinsReturn(prepareStatus, + BitcoinUnits::formatWithUnit( + model->getOptionsModel()->getDisplayUnit(), + m_current_transaction->getTransactionFee())); if (prepareStatus.status != WalletModel::OK) { fNewRecipientAllowed = true; - return; + return false; } - Amount txFee = currentTransaction.getTransactionFee(); - - // Format confirmation message + Amount txFee = m_current_transaction->getTransactionFee(); QStringList formatted; - for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients()) { + for (const SendCoinsRecipient &rcp : + m_current_transaction->getRecipients()) { // generate amount string with wallet name in case of multiwallet QString amount = BitcoinUnits::formatWithUnit( model->getOptionsModel()->getDisplayUnit(), rcp.amount); @@ -348,50 +346,50 @@ formatted.append(recipientElement); } - QString questionString; if (model->wallet().privateKeysDisabled()) { - questionString.append(tr("Do you want to draft this transaction?")); + question_string.append(tr("Do you want to draft this transaction?")); } else { - questionString.append(tr("Are you sure you want to send?")); + question_string.append(tr("Are you sure you want to send?")); } - questionString.append("
"); + question_string.append("
"); if (model->wallet().privateKeysDisabled()) { - questionString.append( + question_string.append( tr("Please, review your transaction proposal. This will produce a " "Partially Signed Bitcoin Transaction (PSBT) which you can copy " "and then sign with e.g. an offline %1 wallet, or a " "PSBT-compatible hardware wallet.") .arg(PACKAGE_NAME)); } else { - questionString.append(tr("Please, review your transaction.")); + question_string.append(tr("Please, review your transaction.")); } - questionString.append("%1"); + question_string.append("
%1"); if (txFee > Amount::zero()) { // append fee string if a fee is required - questionString.append("
"); - questionString.append(tr("Transaction fee")); - questionString.append(""); + question_string.append("
"); + question_string.append(tr("Transaction fee")); + question_string.append(""); // append transaction size - questionString.append( + question_string.append( " (" + - QString::number((double)currentTransaction.getTransactionSize() / - 1000) + + QString::number( + (double)m_current_transaction->getTransactionSize() / 1000) + " kB): "); // append transaction fee value - questionString.append( + question_string.append( ""); - questionString.append(BitcoinUnits::formatHtmlWithUnit( + question_string.append(BitcoinUnits::formatHtmlWithUnit( model->getOptionsModel()->getDisplayUnit(), txFee)); - questionString.append("
"); + question_string.append("
"); } // add total amount in all subdivision units - questionString.append("
"); - Amount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; + question_string.append("
"); + Amount totalAmount = + m_current_transaction->getTotalTransactionAmount() + txFee; QStringList alternativeUnits; for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { if (u != model->getOptionsModel()->getDisplayUnit()) { @@ -399,26 +397,38 @@ BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); } } - questionString.append( + question_string.append( QString("%1: %2") .arg(tr("Total Amount")) .arg(BitcoinUnits::formatHtmlWithUnit( model->getOptionsModel()->getDisplayUnit(), totalAmount))); - questionString.append( + question_string.append( QString("
(=%1)") .arg(alternativeUnits.join(" " + tr("or") + " "))); - QString informative_text; - QString detailed_text; if (formatted.size() > 1) { - questionString = questionString.arg(""); + question_string = question_string.arg(""); informative_text = tr("To review recipient list click \"Show Details...\""); detailed_text = formatted.join("\n\n"); } else { - questionString = questionString.arg("

" + formatted.at(0)); + question_string = question_string.arg("

" + formatted.at(0)); + } + + return true; +} + +void SendCoinsDialog::on_sendButton_clicked() { + if (!model || !model->getOptionsModel()) { + return; + } + + QString question_string, informative_text, detailed_text; + if (!PrepareSendText(question_string, informative_text, detailed_text)) { + return; } + assert(m_current_transaction); const QString confirmation = model->wallet().privateKeysDisabled() ? tr("Confirm transaction proposal") @@ -427,7 +437,7 @@ ? tr("Copy PSBT to clipboard") : tr("Send"); SendConfirmationDialog confirmationDialog( - confirmation, questionString, informative_text, detailed_text, + confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this); confirmationDialog.exec(); QMessageBox::StandardButton retval = @@ -441,7 +451,7 @@ bool send_failure = false; if (model->wallet().privateKeysDisabled()) { CMutableTransaction mtx = - CMutableTransaction{*(currentTransaction.getWtx())}; + CMutableTransaction{*(m_current_transaction->getWtx())}; PartiallySignedTransaction psbtx(mtx); bool complete = false; const TransactionError err = model->wallet().fillPSBT( @@ -458,12 +468,12 @@ } else { // now send the prepared transaction WalletModel::SendCoinsReturn sendStatus = - model->sendCoins(currentTransaction); + model->sendCoins(*m_current_transaction); // process sendStatus and on error generate message shown to user processSendCoinsReturn(sendStatus); if (sendStatus.status == WalletModel::OK) { - Q_EMIT coinsSent(currentTransaction.getWtx()->GetId()); + Q_EMIT coinsSent(m_current_transaction->getWtx()->GetId()); } else { send_failure = true; }