[gui] watch-only wallet: copy PSBT to clipboard

This commit is contained in:
Sjors Provoost 2019-09-26 11:31:49 +02:00
parent 39465d545d
commit c6dd565c88
No known key found for this signature in database
GPG key ID: 57FF9BDBCC301009
3 changed files with 56 additions and 20 deletions

View file

@ -21,11 +21,12 @@
#include <chainparams.h> #include <chainparams.h>
#include <interfaces/node.h> #include <interfaces/node.h>
#include <key_io.h> #include <key_io.h>
#include <wallet/coincontrol.h>
#include <ui_interface.h>
#include <txmempool.h>
#include <policy/fees.h> #include <policy/fees.h>
#include <txmempool.h>
#include <ui_interface.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h> #include <wallet/fees.h>
#include <wallet/psbtwallet.h>
#include <QFontMetrics> #include <QFontMetrics>
#include <QScrollBar> #include <QScrollBar>
@ -186,6 +187,11 @@ void SendCoinsDialog::setModel(WalletModel *_model)
// set default rbf checkbox state // set default rbf checkbox state
ui->optInRBF->setCheckState(Qt::Checked); ui->optInRBF->setCheckState(Qt::Checked);
if (model->privateKeysDisabled()) {
ui->sendButton->setText(tr("Cr&eate Unsigned"));
ui->sendButton->setToolTip(tr("Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME));
}
// set the smartfee-sliders default value (wallets default conf.target or last stored value) // set the smartfee-sliders default value (wallets default conf.target or last stored value)
QSettings settings; QSettings settings;
if (settings.value("nSmartFeeSliderPosition").toInt() != 0) { if (settings.value("nSmartFeeSliderPosition").toInt() != 0) {
@ -305,9 +311,19 @@ void SendCoinsDialog::on_sendButton_clicked()
formatted.append(recipientElement); formatted.append(recipientElement);
} }
QString questionString = tr("Are you sure you want to send?"); QString questionString;
if (model->privateKeysDisabled()) {
questionString.append(tr("Do you want to draft this transaction?"));
} else {
questionString.append(tr("Are you sure you want to send?"));
}
questionString.append("<br /><span style='font-size:10pt;'>"); questionString.append("<br /><span style='font-size:10pt;'>");
questionString.append(tr("Please, review your transaction.")); if (model->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));
} else {
questionString.append(tr("Please, review your transaction."));
}
questionString.append("</span>%1"); questionString.append("</span>%1");
if(txFee > 0) if(txFee > 0)
@ -358,8 +374,9 @@ void SendCoinsDialog::on_sendButton_clicked()
} else { } else {
questionString = questionString.arg("<br /><br />" + formatted.at(0)); questionString = questionString.arg("<br /><br />" + formatted.at(0));
} }
const QString confirmation = model->privateKeysDisabled() ? tr("Confirm transaction proposal") : tr("Confirm send coins");
SendConfirmationDialog confirmationDialog(tr("Confirm send coins"), questionString, informative_text, detailed_text, SEND_CONFIRM_DELAY, this); const QString confirmButtonText = model->privateKeysDisabled() ? tr("Copy PSBT to clipboard") : tr("Send");
SendConfirmationDialog confirmationDialog(confirmation, questionString, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this);
confirmationDialog.exec(); confirmationDialog.exec();
QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result()); QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
@ -369,17 +386,35 @@ void SendCoinsDialog::on_sendButton_clicked()
return; return;
} }
// now send the prepared transaction bool send_failure = false;
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(currentTransaction); if (model->privateKeysDisabled()) {
// process sendStatus and on error generate message shown to user CMutableTransaction mtx = CMutableTransaction{*(currentTransaction.getWtx())};
processSendCoinsReturn(sendStatus); PartiallySignedTransaction psbtx(mtx);
bool complete = false;
const TransactionError err = model->wallet().fillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */);
assert(!complete);
assert(err == TransactionError::OK);
// Serialize the PSBT
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);
} else {
// now send the prepared transaction
WalletModel::SendCoinsReturn sendStatus = model->sendCoins(currentTransaction);
// process sendStatus and on error generate message shown to user
processSendCoinsReturn(sendStatus);
if (sendStatus.status == WalletModel::OK) if (sendStatus.status == WalletModel::OK) {
{ Q_EMIT coinsSent(currentTransaction.getWtx()->GetHash());
} else {
send_failure = true;
}
}
if (!send_failure) {
accept(); accept();
CoinControlDialog::coinControl()->UnSelectAll(); CoinControlDialog::coinControl()->UnSelectAll();
coinControlUpdateLabels(); coinControlUpdateLabels();
Q_EMIT coinsSent(currentTransaction.getWtx()->GetHash());
} }
fNewRecipientAllowed = true; fNewRecipientAllowed = true;
} }
@ -875,8 +910,8 @@ void SendCoinsDialog::coinControlUpdateLabels()
} }
} }
SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, QWidget* parent) SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, const QString& _confirmButtonText, QWidget* parent)
: QMessageBox(parent), secDelay(_secDelay) : QMessageBox(parent), secDelay(_secDelay), confirmButtonText(_confirmButtonText)
{ {
setIcon(QMessageBox::Question); setIcon(QMessageBox::Question);
setWindowTitle(title); // On macOS, the window title is ignored (as required by the macOS Guidelines). setWindowTitle(title); // On macOS, the window title is ignored (as required by the macOS Guidelines).
@ -913,11 +948,11 @@ void SendConfirmationDialog::updateYesButton()
if(secDelay > 0) if(secDelay > 0)
{ {
yesButton->setEnabled(false); yesButton->setEnabled(false);
yesButton->setText(tr("Send") + " (" + QString::number(secDelay) + ")"); yesButton->setText(confirmButtonText + " (" + QString::number(secDelay) + ")");
} }
else else
{ {
yesButton->setEnabled(true); yesButton->setEnabled(true);
yesButton->setText(tr("Send")); yesButton->setText(confirmButtonText);
} }
} }

View file

@ -108,7 +108,7 @@ class SendConfirmationDialog : public QMessageBox
Q_OBJECT Q_OBJECT
public: public:
SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, QWidget* parent = nullptr); SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "Send", QWidget* parent = nullptr);
int exec(); int exec();
private Q_SLOTS: private Q_SLOTS:
@ -119,6 +119,7 @@ private:
QAbstractButton *yesButton; QAbstractButton *yesButton;
QTimer countDownTimer; QTimer countDownTimer;
int secDelay; int secDelay;
QString confirmButtonText;
}; };
#endif // BITCOIN_QT_SENDCOINSDIALOG_H #endif // BITCOIN_QT_SENDCOINSDIALOG_H

View file

@ -183,7 +183,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
std::string strFailReason; std::string strFailReason;
auto& newTx = transaction.getWtx(); auto& newTx = transaction.getWtx();
newTx = m_wallet->createTransaction(vecSend, coinControl, true /* sign */, nChangePosRet, nFeeRequired, strFailReason); newTx = m_wallet->createTransaction(vecSend, coinControl, !privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, strFailReason);
transaction.setTransactionFee(nFeeRequired); transaction.setTransactionFee(nFeeRequired);
if (fSubtractFeeFromAmount && newTx) if (fSubtractFeeFromAmount && newTx)
transaction.reassignAmounts(nChangePosRet); transaction.reassignAmounts(nChangePosRet);