From 6ab3aad9a51cc5e97a8e2ae7dbd5082272163c30 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Mon, 18 Nov 2019 15:54:39 +0100 Subject: [gui] send dialog: split on_sendButton_clicked This commit does not change behavior. --- src/qt/sendcoinsdialog.cpp | 93 ++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 44 deletions(-) (limited to 'src/qt/sendcoinsdialog.cpp') diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index a8c82aaf6c..75c300584f 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -219,11 +219,8 @@ SendCoinsDialog::~SendCoinsDialog() delete ui; } -void SendCoinsDialog::on_sendButton_clicked() +bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informative_text, QString& detailed_text) { - if(!model || !model->getOptionsModel()) - return; - QList recipients; bool valid = true; @@ -246,7 +243,7 @@ void SendCoinsDialog::on_sendButton_clicked() if(!valid || recipients.isEmpty()) { - return; + return false; } fNewRecipientAllowed = false; @@ -255,11 +252,11 @@ void SendCoinsDialog::on_sendButton_clicked() { // Unlock wallet was cancelled fNewRecipientAllowed = true; - return; + return false; } // prepare transaction for getting txFee earlier - WalletModelTransaction currentTransaction(recipients); + m_current_transaction = MakeUnique(recipients); WalletModel::SendCoinsReturn prepareStatus; // Always use a CCoinControl instance, use the CoinControlDialog instance if CoinControl has been enabled @@ -269,22 +266,20 @@ void SendCoinsDialog::on_sendButton_clicked() 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())); + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), m_current_transaction->getTransactionFee())); if(prepareStatus.status != WalletModel::OK) { fNewRecipientAllowed = true; - return; + return false; } - CAmount txFee = currentTransaction.getTransactionFee(); - - // Format confirmation message + CAmount 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); @@ -311,72 +306,82 @@ void SendCoinsDialog::on_sendButton_clicked() 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(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)); + 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 > 0) { // 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(" (" + QString::number((double)currentTransaction.getTransactionSize() / 1000) + " kB): "); + question_string.append(" (" + QString::number((double)m_current_transaction->getTransactionSize() / 1000) + " kB): "); // append transaction fee value - questionString.append(""); - questionString.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee)); - questionString.append("
"); + question_string.append(""); + question_string.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee)); + question_string.append("
"); // append RBF message according to transaction's signalling - questionString.append(""); + question_string.append(""); if (ui->optInRBF->isChecked()) { - questionString.append(tr("You can increase the fee later (signals Replace-By-Fee, BIP-125).")); + question_string.append(tr("You can increase the fee later (signals Replace-By-Fee, BIP-125).")); } else { - questionString.append(tr("Not signalling Replace-By-Fee, BIP-125.")); + question_string.append(tr("Not signalling Replace-By-Fee, BIP-125.")); } - questionString.append(""); + question_string.append(""); } // add total amount in all subdivision units - questionString.append("
"); - CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; + question_string.append("
"); + CAmount totalAmount = m_current_transaction->getTotalTransactionAmount() + txFee; QStringList alternativeUnits; for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); } - questionString.append(QString("%1: %2").arg(tr("Total Amount")) + question_string.append(QString("%1: %2").arg(tr("Total Amount")) .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); - questionString.append(QString("
(=%1)") + 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") : tr("Confirm send coins"); const QString confirmButtonText = model->wallet().privateKeysDisabled() ? tr("Copy PSBT to clipboard") : tr("Send"); - SendConfirmationDialog confirmationDialog(confirmation, questionString, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this); + SendConfirmationDialog confirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this); confirmationDialog.exec(); QMessageBox::StandardButton retval = static_cast(confirmationDialog.result()); @@ -388,7 +393,7 @@ void SendCoinsDialog::on_sendButton_clicked() bool send_failure = false; if (model->wallet().privateKeysDisabled()) { - CMutableTransaction mtx = CMutableTransaction{*(currentTransaction.getWtx())}; + CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())}; PartiallySignedTransaction psbtx(mtx); bool complete = false; const TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, psbtx, complete); @@ -401,12 +406,12 @@ void SendCoinsDialog::on_sendButton_clicked() Q_EMIT message(tr("PSBT copied"), "Copied to clipboard", CClientUIInterface::MSG_INFORMATION); } else { // now send the prepared transaction - WalletModel::SendCoinsReturn sendStatus = model->sendCoins(currentTransaction); + WalletModel::SendCoinsReturn sendStatus = 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()->GetHash()); + Q_EMIT coinsSent(m_current_transaction->getWtx()->GetHash()); } else { send_failure = true; } -- cgit v1.2.3 From f6895301f768220f3ea70231d5cc5b45ecbf4488 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Mon, 18 Nov 2019 16:43:57 +0100 Subject: [gui] save PSBT to file co-authored-by: Glenn Willen --- src/qt/sendcoinsdialog.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) (limited to 'src/qt/sendcoinsdialog.cpp') diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 75c300584f..018f237d5e 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -314,7 +314,7 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa question_string.append("
"); if (model->wallet().privateKeysDisabled()) { - 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)); + 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)); } else { question_string.append(tr("Please, review your transaction.")); } @@ -380,7 +380,7 @@ void SendCoinsDialog::on_sendButton_clicked() assert(m_current_transaction); const QString confirmation = model->wallet().privateKeysDisabled() ? tr("Confirm transaction proposal") : tr("Confirm send coins"); - const QString confirmButtonText = model->wallet().privateKeysDisabled() ? tr("Copy PSBT to clipboard") : tr("Send"); + const QString confirmButtonText = model->wallet().privateKeysDisabled() ? tr("Create Unsigned") : tr("Send"); SendConfirmationDialog confirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this); confirmationDialog.exec(); QMessageBox::StandardButton retval = static_cast(confirmationDialog.result()); @@ -403,7 +403,43 @@ void SendCoinsDialog::on_sendButton_clicked() CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str()); - Q_EMIT message(tr("PSBT copied"), "Copied to clipboard", CClientUIInterface::MSG_INFORMATION); + QMessageBox msgBox; + msgBox.setText("Unsigned Transaction"); + msgBox.setInformativeText("The PSBT has been copied to the clipboard. You can also save it."); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard); + msgBox.setDefaultButton(QMessageBox::Discard); + switch (msgBox.exec()) { + case QMessageBox::Save: { + QString selectedFilter; + QString fileNameSuggestion = ""; + bool first = true; + for (const SendCoinsRecipient &rcp : m_current_transaction->getRecipients()) { + if (!first) { + fileNameSuggestion.append(" - "); + } + QString labelOrAddress = rcp.label.isEmpty() ? rcp.address : rcp.label; + QString amount = BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); + fileNameSuggestion.append(labelOrAddress + "-" + amount); + first = false; + } + fileNameSuggestion.append(".psbt"); + QString filename = GUIUtil::getSaveFileName(this, + tr("Save Transaction Data"), fileNameSuggestion, + tr("Partially Signed Transaction (Binary) (*.psbt)"), &selectedFilter); + if (filename.isEmpty()) { + return; + } + std::ofstream out(filename.toLocal8Bit().data()); + out << ssTx.str(); + out.close(); + Q_EMIT message(tr("PSBT saved"), "PSBT saved to disk", CClientUIInterface::MSG_INFORMATION); + break; + } + case QMessageBox::Discard: + break; + default: + assert(false); + } } else { // now send the prepared transaction WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction); @@ -422,10 +458,13 @@ void SendCoinsDialog::on_sendButton_clicked() coinControlUpdateLabels(); } fNewRecipientAllowed = true; + m_current_transaction.reset(); } void SendCoinsDialog::clear() { + m_current_transaction.reset(); + // Clear coin control settings CoinControlDialog::coinControl()->UnSelectAll(); ui->checkBoxCoinControlChange->setChecked(false); -- cgit v1.2.3