aboutsummaryrefslogtreecommitdiff
path: root/src/qt/sendcoinsdialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/sendcoinsdialog.cpp')
-rw-r--r--src/qt/sendcoinsdialog.cpp138
1 files changed, 72 insertions, 66 deletions
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 12d2d0f31c..05c5ccbfe2 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -22,7 +22,7 @@
#include "ui_interface.h"
#include "txmempool.h"
#include "policy/fees.h"
-#include "wallet/wallet.h"
+#include "wallet/fees.h"
#include <QFontMetrics>
#include <QMessageBox>
@@ -31,6 +31,25 @@
#include <QTextDocument>
#include <QTimer>
+static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} };
+int getConfTargetForIndex(int index) {
+ if (index+1 > static_cast<int>(confTargets.size())) {
+ return confTargets.back();
+ }
+ if (index < 0) {
+ return confTargets[0];
+ }
+ return confTargets[index];
+}
+int getIndexForConfTarget(int target) {
+ for (unsigned int i = 0; i < confTargets.size(); i++) {
+ if (confTargets[i] >= target) {
+ return i;
+ }
+ }
+ return confTargets.size() - 1;
+}
+
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
@@ -152,35 +171,41 @@ void SendCoinsDialog::setModel(WalletModel *_model)
coinControlUpdateLabels();
// fee section
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateSmartFeeLabel()));
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateGlobalFeeVariables()));
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ for (const int &n : confTargets) {
+ ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));
+ }
+ connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSmartFeeLabel()));
+ connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls()));
- connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(updateGlobalFeeVariables()));
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
- connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
- ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
+ connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
+ connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ ui->customFee->setSingleStep(GetRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel();
- updateGlobalFeeVariables();
// set default rbf checkbox state
ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
// set the smartfee-sliders default value (wallets default conf.target or last stored value)
QSettings settings;
- if (settings.value("nSmartFeeSliderPosition").toInt() == 0)
- ui->sliderSmartFee->setValue(ui->sliderSmartFee->maximum() - model->getDefaultConfirmTarget() + 2);
+ if (settings.value("nSmartFeeSliderPosition").toInt() != 0) {
+ // migrate nSmartFeeSliderPosition to nConfTarget
+ // nConfTarget is available since 0.15 (replaced nSmartFeeSliderPosition)
+ int nConfirmTarget = 25 - settings.value("nSmartFeeSliderPosition").toInt(); // 25 == old slider range
+ settings.setValue("nConfTarget", nConfirmTarget);
+ settings.remove("nSmartFeeSliderPosition");
+ }
+ if (settings.value("nConfTarget").toInt() == 0)
+ ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->getDefaultConfirmTarget()));
else
- ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
+ ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));
}
}
@@ -190,7 +215,7 @@ SendCoinsDialog::~SendCoinsDialog()
settings.setValue("fFeeSectionMinimized", fFeeMinimized);
settings.setValue("nFeeRadio", ui->groupFee->checkedId());
settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId());
- settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value());
+ settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex()));
settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());
@@ -243,14 +268,10 @@ void SendCoinsDialog::on_sendButton_clicked()
CCoinControl ctrl;
if (model->getOptionsModel()->getCoinControlFeatures())
ctrl = *CoinControlDialog::coinControl;
- if (ui->radioSmartFee->isChecked())
- ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- else
- ctrl.nConfirmTarget = 0;
- ctrl.signalRbf = ui->optInRBF->isChecked();
+ updateCoinControlState(ctrl);
- prepareStatus = model->prepareTransaction(currentTransaction, &ctrl);
+ prepareStatus = model->prepareTransaction(currentTransaction, ctrl);
// process prepareStatus and on error generate message shown to user
processSendCoinsReturn(prepareStatus,
@@ -589,41 +610,22 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
void SendCoinsDialog::setMinimumFee()
{
ui->radioCustomPerKilobyte->setChecked(true);
- ui->customFee->setValue(CWallet::GetRequiredFee(1000));
+ ui->customFee->setValue(GetRequiredFee(1000));
}
void SendCoinsDialog::updateFeeSectionControls()
{
- ui->sliderSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
+ ui->confTargetSelector ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee2 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee3 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked());
- ui->labelSmartFeeNormal ->setEnabled(ui->radioSmartFee->isChecked());
- ui->labelSmartFeeFast ->setEnabled(ui->radioSmartFee->isChecked());
- ui->confirmationTargetLabel ->setEnabled(ui->radioSmartFee->isChecked());
ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked());
ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked());
ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
}
-void SendCoinsDialog::updateGlobalFeeVariables()
-{
- if (ui->radioSmartFee->isChecked())
- {
- int nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- payTxFee = CFeeRate(0);
-
- // show the estimated required time for confirmation
- ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget * Params().GetConsensus().nPowTargetSpacing) + " / " + tr("%n block(s)", "", nConfirmTarget));
- }
- else
- {
- payTxFee = CFeeRate(ui->customFee->value());
- }
-}
-
void SendCoinsDialog::updateFeeMinimizedLabel()
{
if(!model || !model->getOptionsModel())
@@ -641,22 +643,36 @@ void SendCoinsDialog::updateMinFeeLabel()
{
if (model && model->getOptionsModel())
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
- BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB")
+ BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), GetRequiredFee(1000)) + "/kB")
);
}
+void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl)
+{
+ if (ui->radioCustomFee->isChecked()) {
+ ctrl.m_feerate = CFeeRate(ui->customFee->value());
+ } else {
+ ctrl.m_feerate.reset();
+ }
+ // Avoid using global defaults when sending money from the GUI
+ // Either custom fee will be used or if not selected, the confirmation target from dropdown box
+ ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
+ ctrl.signalRbf = ui->optInRBF->isChecked();
+}
+
void SendCoinsDialog::updateSmartFeeLabel()
{
if(!model || !model->getOptionsModel())
return;
-
- int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
+ CCoinControl coin_control;
+ updateCoinControlState(coin_control);
+ coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
FeeCalculation feeCalc;
- CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &feeCalc, ::mempool);
- if (feeRate <= CFeeRate(0)) // not enough data => minfee
- {
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
- std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
+ CFeeRate feeRate = CFeeRate(GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
+
+ ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
+
+ if (feeCalc.reason == FeeReason::FALLBACK) {
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
ui->labelFeeEstimation->setText("");
ui->fallbackFeeWarningLabel->setVisible(true);
@@ -667,8 +683,6 @@ void SendCoinsDialog::updateSmartFeeLabel()
}
else
{
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
- std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
ui->labelSmartFee2->hide();
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", feeCalc.returnedTarget));
ui->fallbackFeeWarningLabel->setVisible(false);
@@ -727,8 +741,6 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
if (!checked && model) // coin control features disabled
CoinControlDialog::coinControl->SetNull();
- // make sure we set back the confirmation target
- updateGlobalFeeVariables();
coinControlUpdateLabels();
}
@@ -765,22 +777,19 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
CoinControlDialog::coinControl->destChange = CNoDestination();
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
- CBitcoinAddress addr = CBitcoinAddress(text.toStdString());
+ const CTxDestination dest = DecodeDestination(text.toStdString());
if (text.isEmpty()) // Nothing entered
{
ui->labelCoinControlChangeLabel->setText("");
}
- else if (!addr.IsValid()) // Invalid address
+ else if (!IsValidDestination(dest)) // Invalid address
{
ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
}
else // Valid address
{
- CKeyID keyid;
- addr.GetKeyID(keyid);
- if (!model->havePrivKey(keyid)) // Unknown change address
- {
+ if (!model->IsSpendable(dest)) {
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
// confirmation dialog
@@ -788,7 +797,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
if(btnRetVal == QMessageBox::Yes)
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
else
{
ui->lineEditCoinControlChange->setText("");
@@ -807,7 +816,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
else
ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
}
}
}
@@ -819,14 +828,11 @@ void SendCoinsDialog::coinControlUpdateLabels()
if (!model || !model->getOptionsModel())
return;
+ updateCoinControlState(*CoinControlDialog::coinControl);
+
// set pay amounts
CoinControlDialog::payAmounts.clear();
CoinControlDialog::fSubtractFeeFromAmount = false;
- if (ui->radioSmartFee->isChecked()) {
- CoinControlDialog::coinControl->nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- } else {
- CoinControlDialog::coinControl->nConfirmTarget = model->getDefaultConfirmTarget();
- }
for(int i = 0; i < ui->entries->count(); ++i)
{