aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/qt/bitcoingui.cpp8
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/qt/walletframe.cpp8
-rw-r--r--src/qt/walletframe.h3
-rw-r--r--src/qt/walletview.cpp78
-rw-r--r--src/qt/walletview.h2
6 files changed, 102 insertions, 0 deletions
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 2918676c22..370c5da9d0 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -317,6 +317,8 @@ void BitcoinGUI::createActions()
signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
verifyMessageAction = new QAction(tr("&Verify message..."), this);
verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
+ m_load_psbt_action = new QAction(tr("Load PSBT..."), this);
+ m_load_psbt_action->setStatusTip(tr("Load Partially Signed Bitcoin Transaction"));
openRPCConsoleAction = new QAction(tr("Node window"), this);
openRPCConsoleAction->setStatusTip(tr("Open node debugging and diagnostic console"));
@@ -366,6 +368,7 @@ void BitcoinGUI::createActions()
connect(changePassphraseAction, &QAction::triggered, walletFrame, &WalletFrame::changePassphrase);
connect(signMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(signMessageAction, &QAction::triggered, [this]{ gotoSignMessageTab(); });
+ connect(m_load_psbt_action, &QAction::triggered, [this]{ gotoLoadPSBT(); });
connect(verifyMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(verifyMessageAction, &QAction::triggered, [this]{ gotoVerifyMessageTab(); });
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
@@ -438,6 +441,7 @@ void BitcoinGUI::createMenuBar()
file->addAction(backupWalletAction);
file->addAction(signMessageAction);
file->addAction(verifyMessageAction);
+ file->addAction(m_load_psbt_action);
file->addSeparator();
}
file->addAction(quitAction);
@@ -854,6 +858,10 @@ void BitcoinGUI::gotoVerifyMessageTab(QString addr)
{
if (walletFrame) walletFrame->gotoVerifyMessageTab(addr);
}
+void BitcoinGUI::gotoLoadPSBT()
+{
+ if (walletFrame) walletFrame->gotoLoadPSBT();
+}
#endif // ENABLE_WALLET
void BitcoinGUI::updateNetworkState()
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 809cf8b4ed..5592770d36 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -135,6 +135,7 @@ private:
QAction* usedReceivingAddressesAction = nullptr;
QAction* signMessageAction = nullptr;
QAction* verifyMessageAction = nullptr;
+ QAction* m_load_psbt_action = nullptr;
QAction* aboutAction = nullptr;
QAction* receiveCoinsAction = nullptr;
QAction* receiveCoinsMenuAction = nullptr;
@@ -270,6 +271,8 @@ public Q_SLOTS:
void gotoSignMessageTab(QString addr = "");
/** Show Sign/Verify Message dialog and switch to verify message tab */
void gotoVerifyMessageTab(QString addr = "");
+ /** Show load Partially Signed Bitcoin Transaction dialog */
+ void gotoLoadPSBT();
/** Show open dialog */
void openClicked();
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index dac3326cc4..02a9583ae9 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -163,6 +163,14 @@ void WalletFrame::gotoVerifyMessageTab(QString addr)
walletView->gotoVerifyMessageTab(addr);
}
+void WalletFrame::gotoLoadPSBT()
+{
+ WalletView *walletView = currentWalletView();
+ if (walletView) {
+ walletView->gotoLoadPSBT();
+ }
+}
+
void WalletFrame::encryptWallet(bool status)
{
WalletView *walletView = currentWalletView();
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 20fad08b0e..d90ade5005 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -78,6 +78,9 @@ public Q_SLOTS:
/** Show Sign/Verify Message dialog and switch to verify message tab */
void gotoVerifyMessageTab(QString addr = "");
+ /** Load Partially Signed Bitcoin Transaction */
+ void gotoLoadPSBT();
+
/** Encrypt the wallet */
void encryptWallet(bool status);
/** Backup the wallet */
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index bdcb82e06b..d0eca1a25b 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -4,6 +4,9 @@
#include <qt/walletview.h>
+#include <node/psbt.h>
+#include <node/transaction.h>
+#include <policy/policy.h>
#include <qt/addressbookpage.h>
#include <qt/askpassphrasedialog.h>
#include <qt/clientmodel.h>
@@ -20,6 +23,7 @@
#include <interfaces/node.h>
#include <ui_interface.h>
+#include <util/strencodings.h>
#include <QAction>
#include <QActionGroup>
@@ -197,6 +201,80 @@ void WalletView::gotoVerifyMessageTab(QString addr)
signVerifyMessageDialog->setAddress_VM(addr);
}
+void WalletView::gotoLoadPSBT()
+{
+ QString filename = GUIUtil::getOpenFileName(this,
+ tr("Load Transaction Data"), QString(),
+ tr("Partially Signed Transaction (*.psbt)"), nullptr);
+ if (filename.isEmpty()) return;
+ if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) == MAX_FILE_SIZE_PSBT) {
+ Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR);
+ return;
+ }
+ std::ifstream in(filename.toLocal8Bit().data(), std::ios::binary);
+ std::string data(std::istreambuf_iterator<char>{in}, {});
+
+ std::string error;
+ PartiallySignedTransaction psbtx;
+ if (!DecodeRawPSBT(psbtx, data, error)) {
+ Q_EMIT message(tr("Error"), tr("Unable to decode PSBT file") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
+ return;
+ }
+
+ CMutableTransaction mtx;
+ bool complete = false;
+ PSBTAnalysis analysis = AnalyzePSBT(psbtx);
+ QMessageBox msgBox;
+ msgBox.setText("PSBT");
+ switch (analysis.next) {
+ case PSBTRole::CREATOR:
+ case PSBTRole::UPDATER:
+ msgBox.setInformativeText("PSBT is incomplete. Copy to clipboard for manual inspection?");
+ break;
+ case PSBTRole::SIGNER:
+ msgBox.setInformativeText("Transaction needs more signatures. Copy to clipboard?");
+ break;
+ case PSBTRole::FINALIZER:
+ case PSBTRole::EXTRACTOR:
+ complete = FinalizeAndExtractPSBT(psbtx, mtx);
+ if (complete) {
+ msgBox.setInformativeText(tr("Would you like to send this transaction?"));
+ } else {
+ // The analyzer missed something, e.g. if there are final_scriptSig/final_scriptWitness
+ // but with invalid signatures.
+ msgBox.setInformativeText(tr("There was an unexpected problem processing the PSBT. Copy to clipboard for manual inspection?"));
+ }
+ }
+
+ msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
+ switch (msgBox.exec()) {
+ case QMessageBox::Yes: {
+ if (complete) {
+ std::string err_string;
+ CTransactionRef tx = MakeTransactionRef(mtx);
+
+ TransactionError result = BroadcastTransaction(*clientModel->node().context(), tx, err_string, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true, /* wait_callback */ false);
+ if (result == TransactionError::OK) {
+ Q_EMIT message(tr("Success"), tr("Broadcasted transaction sucessfully."), CClientUIInterface::MSG_INFORMATION | CClientUIInterface::MODAL);
+ } else {
+ Q_EMIT message(tr("Error"), QString::fromStdString(err_string), CClientUIInterface::MSG_ERROR);
+ }
+ } else {
+ // 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);
+ return;
+ }
+ }
+ case QMessageBox::Cancel:
+ break;
+ default:
+ assert(false);
+ }
+}
+
bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient)
{
return sendCoinsPage->handlePaymentRequest(recipient);
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index 78d870f59f..00a95eeec5 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -83,6 +83,8 @@ public Q_SLOTS:
void gotoSignMessageTab(QString addr = "");
/** Show Sign/Verify Message dialog and switch to verify message tab */
void gotoVerifyMessageTab(QString addr = "");
+ /** Load Partially Signed Bitcoin Transaction */
+ void gotoLoadPSBT();
/** Show incoming transaction notification for new transactions.