mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 05:23:01 +01:00
[Qt] simple fee bumper with user verification
This commit is contained in:
parent
7f2b9e0868
commit
fbf385cc83
@ -31,8 +31,6 @@
|
|||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#define SEND_CONFIRM_DELAY 3
|
|
||||||
|
|
||||||
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
|
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::SendCoinsDialog),
|
ui(new Ui::SendCoinsDialog),
|
||||||
|
@ -100,13 +100,14 @@ Q_SIGNALS:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define SEND_CONFIRM_DELAY 3
|
||||||
|
|
||||||
class SendConfirmationDialog : public QMessageBox
|
class SendConfirmationDialog : public QMessageBox
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0);
|
SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = 0);
|
||||||
int exec();
|
int exec();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "guiutil.h"
|
#include "guiutil.h"
|
||||||
#include "optionsmodel.h"
|
#include "optionsmodel.h"
|
||||||
#include "platformstyle.h"
|
#include "platformstyle.h"
|
||||||
|
#include "sendcoinsdialog.h"
|
||||||
#include "transactiondescdialog.h"
|
#include "transactiondescdialog.h"
|
||||||
#include "transactionfilterproxy.h"
|
#include "transactionfilterproxy.h"
|
||||||
#include "transactionrecord.h"
|
#include "transactionrecord.h"
|
||||||
@ -37,7 +38,7 @@
|
|||||||
|
|
||||||
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
|
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
|
||||||
QWidget(parent), model(0), transactionProxyModel(0),
|
QWidget(parent), model(0), transactionProxyModel(0),
|
||||||
transactionView(0), abandonAction(0), columnResizingFixer(0)
|
transactionView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0)
|
||||||
{
|
{
|
||||||
// Build filter row
|
// Build filter row
|
||||||
setContentsMargins(0,0,0,0);
|
setContentsMargins(0,0,0,0);
|
||||||
@ -138,6 +139,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
|
|||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
abandonAction = new QAction(tr("Abandon transaction"), this);
|
abandonAction = new QAction(tr("Abandon transaction"), this);
|
||||||
|
bumpFeeAction = new QAction(tr("Increase transaction fee"), this);
|
||||||
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
|
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
|
||||||
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
|
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
|
||||||
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
|
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
|
||||||
@ -156,6 +158,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
|
|||||||
contextMenu->addAction(copyTxPlainText);
|
contextMenu->addAction(copyTxPlainText);
|
||||||
contextMenu->addAction(showDetailsAction);
|
contextMenu->addAction(showDetailsAction);
|
||||||
contextMenu->addSeparator();
|
contextMenu->addSeparator();
|
||||||
|
contextMenu->addAction(bumpFeeAction);
|
||||||
contextMenu->addAction(abandonAction);
|
contextMenu->addAction(abandonAction);
|
||||||
contextMenu->addAction(editLabelAction);
|
contextMenu->addAction(editLabelAction);
|
||||||
|
|
||||||
@ -173,6 +176,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
|
|||||||
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
|
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
|
||||||
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
|
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
|
||||||
|
|
||||||
|
connect(bumpFeeAction, SIGNAL(triggered()), this, SLOT(bumpFee()));
|
||||||
connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx()));
|
connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx()));
|
||||||
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
|
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
|
||||||
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
|
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
|
||||||
@ -372,6 +376,7 @@ void TransactionView::contextualMenu(const QPoint &point)
|
|||||||
uint256 hash;
|
uint256 hash;
|
||||||
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
|
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
|
||||||
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
|
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
|
||||||
|
bumpFeeAction->setEnabled(model->transactionSignalsRBF(hash));
|
||||||
|
|
||||||
if(index.isValid())
|
if(index.isValid())
|
||||||
{
|
{
|
||||||
@ -397,6 +402,21 @@ void TransactionView::abandonTx()
|
|||||||
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
|
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TransactionView::bumpFee()
|
||||||
|
{
|
||||||
|
if(!transactionView || !transactionView->selectionModel())
|
||||||
|
return;
|
||||||
|
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
|
||||||
|
|
||||||
|
// get the hash from the TxHashRole (QVariant / QString)
|
||||||
|
uint256 hash;
|
||||||
|
QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
|
||||||
|
hash.SetHex(hashQStr.toStdString());
|
||||||
|
|
||||||
|
// Bump tx fee over the walletModel
|
||||||
|
model->bumpFee(hash);
|
||||||
|
}
|
||||||
|
|
||||||
void TransactionView::copyAddress()
|
void TransactionView::copyAddress()
|
||||||
{
|
{
|
||||||
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
|
||||||
|
@ -76,6 +76,7 @@ private:
|
|||||||
QDateTimeEdit *dateFrom;
|
QDateTimeEdit *dateFrom;
|
||||||
QDateTimeEdit *dateTo;
|
QDateTimeEdit *dateTo;
|
||||||
QAction *abandonAction;
|
QAction *abandonAction;
|
||||||
|
QAction *bumpFeeAction;
|
||||||
|
|
||||||
QWidget *createDateRangeWidget();
|
QWidget *createDateRangeWidget();
|
||||||
|
|
||||||
@ -99,6 +100,7 @@ private Q_SLOTS:
|
|||||||
void openThirdPartyTxUrl(QString url);
|
void openThirdPartyTxUrl(QString url);
|
||||||
void updateWatchOnlyColumn(bool fHaveWatchOnly);
|
void updateWatchOnlyColumn(bool fHaveWatchOnly);
|
||||||
void abandonTx();
|
void abandonTx();
|
||||||
|
void bumpFee();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void doubleClicked(const QModelIndex&);
|
void doubleClicked(const QModelIndex&);
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "guiconstants.h"
|
#include "guiconstants.h"
|
||||||
#include "guiutil.h"
|
#include "guiutil.h"
|
||||||
|
#include "optionsmodel.h"
|
||||||
#include "paymentserver.h"
|
#include "paymentserver.h"
|
||||||
#include "recentrequeststablemodel.h"
|
#include "recentrequeststablemodel.h"
|
||||||
|
#include "sendcoinsdialog.h"
|
||||||
#include "transactiontablemodel.h"
|
#include "transactiontablemodel.h"
|
||||||
|
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
@ -17,15 +19,18 @@
|
|||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "validation.h"
|
#include "validation.h"
|
||||||
#include "net.h" // for g_connman
|
#include "net.h" // for g_connman
|
||||||
|
#include "policy/rbf.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "ui_interface.h"
|
#include "ui_interface.h"
|
||||||
#include "util.h" // for GetBoolArg
|
#include "util.h" // for GetBoolArg
|
||||||
|
#include "wallet/feebumper.h"
|
||||||
#include "wallet/wallet.h"
|
#include "wallet/wallet.h"
|
||||||
#include "wallet/walletdb.h" // for BackupWallet
|
#include "wallet/walletdb.h" // for BackupWallet
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
@ -693,6 +698,71 @@ bool WalletModel::abandonTransaction(uint256 hash) const
|
|||||||
return wallet->AbandonTransaction(hash);
|
return wallet->AbandonTransaction(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WalletModel::transactionSignalsRBF(uint256 hash) const
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, wallet->cs_wallet);
|
||||||
|
const CWalletTx *wtx = wallet->GetWalletTx(hash);
|
||||||
|
if (wtx && SignalsOptInRBF(*wtx))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WalletModel::bumpFee(uint256 hash)
|
||||||
|
{
|
||||||
|
std::unique_ptr<CFeeBumper> feeBump;
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, wallet->cs_wallet);
|
||||||
|
feeBump.reset(new CFeeBumper(wallet, hash, 0, false, 0, true));
|
||||||
|
}
|
||||||
|
if (feeBump->getResult() != BumpFeeResult::OK)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
|
||||||
|
(feeBump->getErrors().size() ? QString::fromStdString(feeBump->getErrors()[0]) : "") +")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow a user based fee verification
|
||||||
|
QString questionString = tr("Do you want to increase the fee from %1 to %2").arg(
|
||||||
|
BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), feeBump->getOldFee()),
|
||||||
|
BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), feeBump->getNewFee()));
|
||||||
|
SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
|
||||||
|
confirmationDialog.exec();
|
||||||
|
QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
|
||||||
|
|
||||||
|
// cancel sign&broadcast if users doesn't want to bump the fee
|
||||||
|
if (retval != QMessageBox::Yes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WalletModel::UnlockContext ctx(requestUnlock());
|
||||||
|
if(!ctx.isValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign bumped transaction
|
||||||
|
bool res = false;
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, wallet->cs_wallet);
|
||||||
|
res = feeBump->signTransaction(wallet);
|
||||||
|
}
|
||||||
|
if (!res) {
|
||||||
|
QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// commit the bumped transaction
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, wallet->cs_wallet);
|
||||||
|
res = feeBump->commit(wallet);
|
||||||
|
}
|
||||||
|
if(!res) {
|
||||||
|
QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
|
||||||
|
QString::fromStdString(feeBump->getErrors()[0])+")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool WalletModel::isWalletEnabled()
|
bool WalletModel::isWalletEnabled()
|
||||||
{
|
{
|
||||||
return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
|
return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
|
||||||
|
@ -207,6 +207,9 @@ public:
|
|||||||
bool transactionCanBeAbandoned(uint256 hash) const;
|
bool transactionCanBeAbandoned(uint256 hash) const;
|
||||||
bool abandonTransaction(uint256 hash) const;
|
bool abandonTransaction(uint256 hash) const;
|
||||||
|
|
||||||
|
bool transactionSignalsRBF(uint256 hash) const;
|
||||||
|
bool bumpFee(uint256 hash);
|
||||||
|
|
||||||
static bool isWalletEnabled();
|
static bool isWalletEnabled();
|
||||||
|
|
||||||
bool hdEnabled() const;
|
bool hdEnabled() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user