Skip to content

Commit 5c3b800

Browse files
committed
qt: Add Create Unsigned button to SendConfirmationDialog
Instead of having different buttons or changing button behavior for making a PSBT, just have SendConfirmationDialog return whether the user wants a PSBT or a broadcasted transaction. Since this dialog is used by both the bumpFeeAction and the SendCoinsDialog, changes to both to support the different behavior is needed. They will check the return value of the SendConfirmationDialog for whether a PSBT needs to be created instead of checking whether private keys are disabled. Strings used in this dialog are being slightly modified to work with both private keys enabled and disabled wallets.
1 parent 571bb94 commit 5c3b800

File tree

3 files changed

+43
-28
lines changed

3 files changed

+43
-28
lines changed

src/qt/sendcoinsdialog.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -324,16 +324,17 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
324324
formatted.append(recipientElement);
325325
}
326326

327-
if (model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner()) {
328-
question_string.append(tr("Do you want to draft this transaction?"));
329-
} else {
330-
question_string.append(tr("Are you sure you want to send?"));
331-
}
332-
327+
/*: Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify
328+
that the displayed transaction details represent the transaction the user intends to create. */
329+
question_string.append(tr("Do you want to create this transaction?"));
333330
question_string.append("<br /><span style='font-size:10pt;'>");
334331
if (model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner()) {
332+
/*: Text to inform a user attempting to create a transaction of their current options. At this stage,
333+
a user can only create a PSBT. This string is displayed when private keys are disabled and an external
334+
signer is not available. */
335335
question_string.append(tr("Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME));
336336
} else {
337+
/*: Text to prompt a user to review the details of the transaction they are attempting to send. */
337338
question_string.append(tr("Please, review your transaction."));
338339
}
339340
question_string.append("</span>%1");
@@ -397,21 +398,20 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
397398
if (!PrepareSendText(question_string, informative_text, detailed_text)) return;
398399
assert(m_current_transaction);
399400

400-
const QString confirmation = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Confirm transaction proposal") : tr("Confirm send coins");
401-
const QString confirmButtonText = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Create Unsigned") : tr("Sign and send");
402-
auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this);
401+
const QString confirmation = tr("Confirm send coins");
402+
auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, !model->wallet().privateKeysDisabled(), true, this);
403403
confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
404404
// TODO: Replace QDialog::exec() with safer QDialog::show().
405405
const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec());
406406

407-
if(retval != QMessageBox::Yes)
407+
if(retval != QMessageBox::Yes && retval != QMessageBox::Save)
408408
{
409409
fNewRecipientAllowed = true;
410410
return;
411411
}
412412

413413
bool send_failure = false;
414-
if (model->wallet().privateKeysDisabled()) {
414+
if (retval == QMessageBox::Save) {
415415
CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())};
416416
PartiallySignedTransaction psbtx(mtx);
417417
bool complete = false;
@@ -512,6 +512,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
512512
assert(false);
513513
} // msgBox.exec()
514514
} else {
515+
assert(!model->wallet().privateKeysDisabled());
515516
// now send the prepared transaction
516517
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction);
517518
// process sendStatus and on error generate message shown to user
@@ -1031,52 +1032,62 @@ void SendCoinsDialog::coinControlUpdateLabels()
10311032
}
10321033
}
10331034

1034-
SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, const QString& _confirmButtonText, QWidget* parent)
1035-
: QMessageBox(parent), secDelay(_secDelay), confirmButtonText(_confirmButtonText)
1035+
SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, bool enable_send, bool always_show_unsigned, QWidget* parent)
1036+
: QMessageBox(parent), secDelay(_secDelay), m_enable_send(enable_send)
10361037
{
10371038
setIcon(QMessageBox::Question);
10381039
setWindowTitle(title); // On macOS, the window title is ignored (as required by the macOS Guidelines).
10391040
setText(text);
10401041
setInformativeText(informative_text);
10411042
setDetailedText(detailed_text);
10421043
setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
1044+
if (always_show_unsigned || !enable_send) addButton(QMessageBox::Save);
10431045
setDefaultButton(QMessageBox::Cancel);
10441046
yesButton = button(QMessageBox::Yes);
10451047
if (confirmButtonText.isEmpty()) {
10461048
confirmButtonText = yesButton->text();
10471049
}
1048-
updateYesButton();
1050+
m_psbt_button = button(QMessageBox::Save);
1051+
updateButtons();
10491052
connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown);
10501053
}
10511054

10521055
int SendConfirmationDialog::exec()
10531056
{
1054-
updateYesButton();
1057+
updateButtons();
10551058
countDownTimer.start(1000);
10561059
return QMessageBox::exec();
10571060
}
10581061

10591062
void SendConfirmationDialog::countDown()
10601063
{
10611064
secDelay--;
1062-
updateYesButton();
1065+
updateButtons();
10631066

10641067
if(secDelay <= 0)
10651068
{
10661069
countDownTimer.stop();
10671070
}
10681071
}
10691072

1070-
void SendConfirmationDialog::updateYesButton()
1073+
void SendConfirmationDialog::updateButtons()
10711074
{
10721075
if(secDelay > 0)
10731076
{
10741077
yesButton->setEnabled(false);
1075-
yesButton->setText(confirmButtonText + " (" + QString::number(secDelay) + ")");
1078+
yesButton->setText(confirmButtonText + (m_enable_send ? (" (" + QString::number(secDelay) + ")") : QString("")));
1079+
if (m_psbt_button) {
1080+
m_psbt_button->setEnabled(false);
1081+
m_psbt_button->setText(m_psbt_button_text + " (" + QString::number(secDelay) + ")");
1082+
}
10761083
}
10771084
else
10781085
{
1079-
yesButton->setEnabled(true);
1086+
yesButton->setEnabled(m_enable_send);
10801087
yesButton->setText(confirmButtonText);
1088+
if (m_psbt_button) {
1089+
m_psbt_button->setEnabled(true);
1090+
m_psbt_button->setText(m_psbt_button_text);
1091+
}
10811092
}
10821093
}

src/qt/sendcoinsdialog.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,18 +114,21 @@ class SendConfirmationDialog : public QMessageBox
114114
Q_OBJECT
115115

116116
public:
117-
SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "", QWidget* parent = nullptr);
117+
SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, bool enable_send = true, bool always_show_unsigned = true, QWidget* parent = nullptr);
118118
int exec() override;
119119

120120
private Q_SLOTS:
121121
void countDown();
122-
void updateYesButton();
122+
void updateButtons();
123123

124124
private:
125125
QAbstractButton *yesButton;
126+
QAbstractButton *m_psbt_button;
126127
QTimer countDownTimer;
127128
int secDelay;
128-
QString confirmButtonText;
129+
QString confirmButtonText{tr("Send")};
130+
bool m_enable_send;
131+
QString m_psbt_button_text{tr("Create Unsigned")};
129132
};
130133

131134
#endif // BITCOIN_QT_SENDCOINSDIALOG_H

src/qt/walletmodel.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -480,10 +480,9 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
480480
return false;
481481
}
482482

483-
const bool create_psbt = m_wallet->privateKeysDisabled();
484-
485483
// allow a user based fee verification
486-
QString questionString = create_psbt ? tr("Do you want to draft a transaction with fee increase?") : tr("Do you want to increase the fee?");
484+
/*: Asks a user if they would like to manually increase the fee of a transaction that has already been created. */
485+
QString questionString = tr("Do you want to increase the fee?");
487486
questionString.append("<br />");
488487
questionString.append("<table style=\"text-align: left;\">");
489488
questionString.append("<tr><td>");
@@ -506,13 +505,13 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
506505
questionString.append(tr("Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy."));
507506
}
508507

509-
auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString);
508+
auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString, "", "", SEND_CONFIRM_DELAY, !m_wallet->privateKeysDisabled(), true, nullptr);
510509
confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
511510
// TODO: Replace QDialog::exec() with safer QDialog::show().
512511
const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec());
513512

514513
// cancel sign&broadcast if user doesn't want to bump the fee
515-
if (retval != QMessageBox::Yes) {
514+
if (retval != QMessageBox::Yes && retval != QMessageBox::Save) {
516515
return false;
517516
}
518517

@@ -523,7 +522,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
523522
}
524523

525524
// Short-circuit if we are returning a bumped transaction PSBT to clipboard
526-
if (create_psbt) {
525+
if (retval == QMessageBox::Save) {
527526
PartiallySignedTransaction psbtx(mtx);
528527
bool complete = false;
529528
const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete);
@@ -539,6 +538,8 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
539538
return true;
540539
}
541540

541+
assert(!m_wallet->privateKeysDisabled());
542+
542543
// sign bumped transaction
543544
if (!m_wallet->signBumpTransaction(mtx)) {
544545
QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't sign transaction."));

0 commit comments

Comments
 (0)