<NME> sendcoinsdialog.cpp
<BEF> // Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sendcoinsdialog.h"
#include "ui_sendcoinsdialog.h"

#include "addresstablemodel.h"
#include "bitcoinunits.h"
#include "clientmodel.h"
#include "coincontroldialog.h"
#include "guiutil.h"
#include "lelantusmodel.h"
#include "optionsmodel.h"
#include "platformstyle.h"
#include "sendcoinsentry.h"
#include "walletmodel.h"

#include "base58.h"
#include "chainparams.h"
#include "lelantus.h"
#include "wallet/coincontrol.h"
#include "validation.h" // mempool and minRelayTxFee
#include "ui_interface.h"
#include "txmempool.h"
#include "wallet/wallet.h"
#include "sendtopcodedialog.h"
#include "pcodemodel.h"

#include <QFontMetrics>
#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QTextDocument>
#include <QTimer>

#define SEND_CONFIRM_DELAY   3

SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::SendCoinsDialog),
    clientModel(0),
    model(0),
    fNewRecipientAllowed(true),
    fFeeMinimized(true),
    fAnonymousMode(true),
    platformStyle(_platformStyle)
{
    ui->setupUi(this);

    if (!_platformStyle->getImagesOnButtons()) {
        ui->addButton->setIcon(QIcon());
        ui->clearButton->setIcon(QIcon());
        ui->sendButton->setIcon(QIcon());
    } else {
        ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add"));
        ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
        ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send"));
    }

    GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);

    addEntry();

    connect(ui->addButton, &QPushButton::clicked, this, &SendCoinsDialog::addEntry);
    connect(ui->clearButton, &QPushButton::clicked, this, &SendCoinsDialog::clear);
    // Coin Control
    connect(ui->pushButtonCoinControl, &QPushButton::clicked, this, &SendCoinsDialog::coinControlButtonClicked);
    connect(ui->checkBoxCoinControlChange, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlChangeChecked);
    connect(ui->lineEditCoinControlChange, &QValidatedLineEdit::textEdited, this, &SendCoinsDialog::coinControlChangeEdited);
    // Coin Control: clipboard actions
    QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
    QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
    QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
    QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
    QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
    QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
    QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
    connect(clipboardQuantityAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardQuantity);
    connect(clipboardAmountAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAmount);
    connect(clipboardFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardFee);
    connect(clipboardAfterFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAfterFee);
    connect(clipboardBytesAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardBytes);
    connect(clipboardLowOutputAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardLowOutput);
    connect(clipboardChangeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardChange);
    ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
    ui->labelCoinControlAmount->addAction(clipboardAmountAction);
    ui->labelCoinControlFee->addAction(clipboardFeeAction);
    ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
    ui->labelCoinControlBytes->addAction(clipboardBytesAction);
    ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
    ui->labelCoinControlChange->addAction(clipboardChangeAction);

    ui->frameCoinControl->setAutoFillBackground(true);
    ui->scrollArea->setAutoFillBackground(true);
    ui->frameFee->setAutoFillBackground(true);

    {
        auto allowed = lelantus::IsLelantusAllowed();
        setAnonymizeMode(allowed);

        if (!allowed) {
            ui->switchFundButton->setEnabled(false);
        }
    }

    // init transaction fee section
    QSettings settings;
    if (!settings.contains("fFeeSectionMinimized"))
        settings.setValue("fFeeSectionMinimized", true);
    if (!settings.contains("nFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility
        settings.setValue("nFeeRadio", 1); // custom
    if (!settings.contains("nFeeRadio"))
        settings.setValue("nFeeRadio", 0); // recommended
    if (!settings.contains("nCustomFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility
        settings.setValue("nCustomFeeRadio", 1); // total at least
    if (!settings.contains("nCustomFeeRadio"))
        settings.setValue("nCustomFeeRadio", 0); // per kilobyte
    if (!settings.contains("nTransactionFee"))
        settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE);
    if (!settings.contains("fPayOnlyMinFee"))
        settings.setValue("fPayOnlyMinFee", false);
    ui->groupFee->setId(ui->radioSmartFee, 0);
    ui->groupFee->setId(ui->radioCustomFee, 1);
    ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);
    ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0);
    ui->groupCustomFee->setId(ui->radioCustomAtLeast, 1);
    ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true);
    ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
    ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
    minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
}

void SendCoinsDialog::setClientModel(ClientModel *_clientModel)
{
    this->clientModel = _clientModel;

    if (_clientModel)
    {
        connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateSmartFeeLabel);
        connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateBlocks);
    }
}

void SendCoinsDialog::setModel(WalletModel *_model)
{
    this->model = _model;

    if(_model && _model->getOptionsModel())
    {
        for(int i = 0; i < ui->entries->count(); ++i)
        {
            SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
            if(entry)
            {
                entry->setModel(_model);
            }
        }

        auto privateBalance = _model->getLelantusModel()->getPrivateBalance();

        setBalance(
            _model->getBalance(), _model->getUnconfirmedBalance(), _model->getImmatureBalance(),
            _model->getWatchBalance(), _model->getWatchUnconfirmedBalance(), _model->getWatchImmatureBalance(),
            privateBalance.first, privateBalance.second, _model->getAnonymizableBalance());

        connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance);
        connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::updateDisplayUnit);
        updateDisplayUnit();

        // Coin Control
        connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
        connect(_model->getOptionsModel(), &OptionsModel::coinControlFeaturesChanged, this, &SendCoinsDialog::coinControlFeatureChanged);
        ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures());
        coinControlUpdateLabels();

        // fee section
        connect(ui->sliderSmartFee, &QSlider::valueChanged, this, &SendCoinsDialog::updateSmartFeeLabel);
        connect(ui->sliderSmartFee, &QSlider::valueChanged, this, &SendCoinsDialog::updateGlobalFeeVariables);
        connect(ui->sliderSmartFee, &QSlider::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
        connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls);
        connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateGlobalFeeVariables);
        connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);
        connect(ui->groupCustomFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateGlobalFeeVariables);
        connect(ui->groupCustomFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);
        connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::updateGlobalFeeVariables);
        connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::setMinimumFee);
        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateFeeSectionControls);
        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateGlobalFeeVariables);
        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
        ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
        updateFeeSectionControls();
        updateMinFeeLabel();
        updateSmartFeeLabel();
        updateGlobalFeeVariables();

        // 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);
        else
            ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
    }
}

SendCoinsDialog::~SendCoinsDialog()
{
    QSettings settings;
    settings.setValue("fFeeSectionMinimized", fFeeMinimized);
    settings.setValue("nFeeRadio", true);
    settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId());
    settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value());
    settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
    settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());

    delete ui;
}

void SendCoinsDialog::on_sendButton_clicked()
{
    updateGlobalFeeVariables();

    if(!model || !model->getOptionsModel())
        return;

    QList<SendCoinsRecipient> recipients;
    bool valid = true;

    using UnlockContext = WalletModel::UnlockContext;
    std::unique_ptr<UnlockContext> ctx;

    for(int i = 0; i < ui->entries->count(); ++i)
    {
        SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
        if(entry)
        {
            if(entry->validate())
            {
                SendCoinsRecipient recipient = entry->getValue();
                if(entry->isPayToPcode()) {
                    if (!model->getPcodeModel()) return;
                    std::unique_ptr<SendtoPcodeDialog> dialog(new SendtoPcodeDialog(this, recipient.address.toStdString(), recipient.label.toStdString()));
                    dialog->setModel(model);
                    dialog->exec();
                    std::pair<SendtoPcodeDialog::Result, CBitcoinAddress> const sendResult = dialog->getResult();
                    switch (sendResult.first) {
                        case SendtoPcodeDialog::Result::addressSelected:
                            recipient.address = sendResult.second.ToString().c_str();
                            break;
                        default:
                            return;
                    }
                    ctx = dialog->getUnlockContext();
                }
                recipients.append(recipient);
            }
            else
            {
                valid = false;
            }
        }
    }

    if(!valid || recipients.isEmpty())
    {
        return;
    }

    fNewRecipientAllowed = false;
    if(!ctx)
    {
        ctx = std::unique_ptr<UnlockContext>(new UnlockContext(model->requestUnlock()));
    }
    if(!ctx->isValid())
    {
        // Unlock wallet was cancelled
        fNewRecipientAllowed = true;
        return;
    }

    // prepare transaction for getting txFee earlier
    WalletModelTransaction currentTransaction(recipients);
    WalletModel::SendCoinsReturn prepareStatus;

    // Always use a CCoinControl instance, use the CoinControlDialog instance if CoinControl has been enabled
    CCoinControl ctrl;
    if (model->getOptionsModel()->getCoinControlFeatures()) {
        ctrl = *CoinControlDialog::coinControl;
        removeUnmatchedOutput(ctrl);
    }
    if (ui->radioSmartFee->isChecked())
        ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
    else
        ctrl.nConfirmTarget = 0;

    if (fAnonymousMode) {
        prepareStatus = model->prepareJoinSplitTransaction(currentTransaction, &ctrl);
    } else {
        prepareStatus = model->prepareTransaction(currentTransaction, &ctrl);
    }

    // process prepareStatus and on error generate message shown to user
    processSendCoinsReturn(prepareStatus,
        BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee()));

    if(prepareStatus.status != WalletModel::OK) {
        fNewRecipientAllowed = true;
        return;
    }

    CAmount txFee = currentTransaction.getTransactionFee();

    // Format confirmation message
    QStringList formatted;
    Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients())
    {
        // generate bold amount string
        QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
        amount.append("</b>");
        // generate monospace address string
        QString address = "<span style='font-family: monospace;'>" + rcp.address;
        address.append("</span>");

        QString recipientElement;

        if (!rcp.paymentRequest.IsInitialized()) // normal payment
        {
            if(rcp.label.length() > 0) // label with address
            {
                recipientElement = tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.label));
                recipientElement.append(QString(" (%1)").arg(address));
            }
            else // just address
            {
                recipientElement = tr("%1 to %2").arg(amount, address);
            }
        }
        else if(!rcp.authenticatedMerchant.isEmpty()) // authenticated payment request
        {
            recipientElement = tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.authenticatedMerchant));
        }
        else // unauthenticated payment request
        {
            recipientElement = tr("%1 to %2").arg(amount, address);
        }

        formatted.append(recipientElement);
    }

    QString questionString = tr("Are you sure you want to send?");
    questionString.append("<br /><br />%1");

    if(txFee > 0)
    {
        // append fee string if a fee is required
        questionString.append("<hr /><span style='color:#aa0000;'>");
        questionString.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
        questionString.append("</span> ");
        questionString.append(tr("added as transaction fee"));

        // append transaction size
        questionString.append(" (" + QString::number((double)currentTransaction.getTransactionSize() / 1000) + " kB)");
    }

    // add total amount in all subdivision units
    questionString.append("<hr />");
    CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee;
    QStringList alternativeUnits;
    Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
    {
        if(u != model->getOptionsModel()->getDisplayUnit())
            alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));
    }
    questionString.append(tr("Total Amount %1")
        .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount)));
    questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
        .arg(alternativeUnits.join(" " + tr("or") + "<br />")));

    SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
        questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
    confirmationDialog.exec();
    QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();

    if(retval != QMessageBox::Yes)
    {
        fNewRecipientAllowed = true;
        return;
    }

    // now send the prepared transaction
    WalletModel::SendCoinsReturn sendStatus;

    if (fAnonymousMode) {
        sendStatus = model->sendPrivateCoins(currentTransaction);
    } else {
        sendStatus = model->sendCoins(currentTransaction);
    }
    // process sendStatus and on error generate message shown to user
    processSendCoinsReturn(sendStatus);

    if (sendStatus.status == WalletModel::OK)
    {
        for(int i = 0; i < ui->entries->count(); ++i)
        {
            SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
            if(entry && entry->isPayToPcode())
            {
                SendCoinsRecipient recipient = entry->getValue();
                model->getPcodeModel()->generateTheirNextAddress(recipient.address.toStdString());
            }
        }
        accept();
        CoinControlDialog::coinControl->UnSelectAll();
        coinControlUpdateLabels();
    }
    fNewRecipientAllowed = true;
}

void SendCoinsDialog::on_switchFundButton_clicked()
{
    setAnonymizeMode(!fAnonymousMode);
    coinControlUpdateLabels();
}

void SendCoinsDialog::clear()
{
    // Remove entries until only one left
    while(ui->entries->count())
    {
        ui->entries->takeAt(0)->widget()->deleteLater();
    }
    addEntry();

    updateTabsAndLabels();
}

void SendCoinsDialog::reject()
{
    clear();
}

void SendCoinsDialog::accept()
{
    clear();
}

SendCoinsEntry *SendCoinsDialog::addEntry()
{
    SendCoinsEntry *entry = new SendCoinsEntry(platformStyle, this);
    entry->setModel(model);
    ui->entries->addWidget(entry);
    connect(entry, &SendCoinsEntry::removeEntry, this, &SendCoinsDialog::removeEntry);
    connect(entry, &SendCoinsEntry::payAmountChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
    connect(entry, &SendCoinsEntry::subtractFeeFromAmountChanged, this, &SendCoinsDialog::coinControlUpdateLabels);

    // Focus the field, so that entry can start immediately
    entry->clear();
    entry->setFocus();
    ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
    qApp->processEvents();
    QScrollBar* bar = ui->scrollArea->verticalScrollBar();
    if(bar)
        bar->setSliderPosition(bar->maximum());

    updateTabsAndLabels();
    return entry;
}

void SendCoinsDialog::updateBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
{
    if (header)
    {
        return;
    }

    auto allowed = lelantus::IsLelantusAllowed(count);

    if (allowed && !ui->switchFundButton->isEnabled())
    {
        setAnonymizeMode(true);
        ui->switchFundButton->setEnabled(true);
    }
    else if (!allowed && ui->switchFundButton->isEnabled())
    {
        setAnonymizeMode(false);
        ui->switchFundButton->setEnabled(false);
    }
}

void SendCoinsDialog::updateTabsAndLabels()
{
    setupTabChain(0);
    coinControlUpdateLabels();
}

void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
{
    entry->hide();

    // If the last entry is about to be removed add an empty one
    if (ui->entries->count() == 1)
        addEntry();

    entry->deleteLater();

    updateTabsAndLabels();
}

QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
{
    for(int i = 0; i < ui->entries->count(); ++i)
    {
        SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
        if(entry)
        {
        msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
        break;
    case WalletModel::DuplicateAddress:
        msgParams.first = tr("Duplicate address found: can only send to each address once per send operation.");
        break;
    case WalletModel::TransactionCreationFailed:
        msgParams.first = tr("Transaction creation failed!");
}

void SendCoinsDialog::setAddress(const QString &address)
{
    SendCoinsEntry *entry = 0;
    // Replace the first entry if it is still unused
    if(ui->entries->count() == 1)
    {
        SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
        if(first->isClear())
        {
            entry = first;
        }
    }
    if(!entry)
    {
        entry = addEntry();
    }

    entry->setAddress(address);
}

void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
{
    if(!fNewRecipientAllowed)
        return;

    SendCoinsEntry *entry = 0;
    // Replace the first entry if it is still unused
    if(ui->entries->count() == 1)
    {
        SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
        if(first->isClear())
        {
            entry = first;
        }
    }
    if(!entry)
    {
        entry = addEntry();
    }

    entry->setValue(rv);
    updateTabsAndLabels();
}

bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)
{
    // Just paste the entry, all pre-checks
    // are done in paymentserver.cpp.
    pasteEntry(rv);
    return true;
}

void SendCoinsDialog::setBalance(
    const CAmount& balance,
    const CAmount& unconfirmedBalance,
    const CAmount& immatureBalance,
    const CAmount& watchBalance,
    const CAmount& watchUnconfirmedBalance,
    const CAmount& watchImmatureBalance,
    const CAmount& privateBalance,
    const CAmount& unconfirmedPrivateBalance,
    const CAmount& anonymizableBalance)
{
    Q_UNUSED(unconfirmedBalance);
    Q_UNUSED(immatureBalance);
    Q_UNUSED(watchBalance);
    Q_UNUSED(watchUnconfirmedBalance);
    Q_UNUSED(watchImmatureBalance);
    Q_UNUSED(unconfirmedPrivateBalance);
    Q_UNUSED(anonymizableBalance);

    if(model && model->getOptionsModel())
    {
        ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
            fAnonymousMode ? privateBalance : balance));
    }
}

void SendCoinsDialog::updateDisplayUnit()
{
    setBalance(model->getBalance(), 0, 0, 0, 0, 0, model->getLelantusModel()->getPrivateBalance().first, 0, 0);
    ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    updateMinFeeLabel();
    updateSmartFeeLabel();
}

void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg)
{
    QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;
    // Default to a warning message, override if error message is needed
    msgParams.second = CClientUIInterface::MSG_WARNING;

    // This comment is specific to SendCoinsDialog usage of WalletModel::SendCoinsReturn.
    // WalletModel::TransactionCommitFailed is used only in WalletModel::sendCoins()
    // all others are used only in WalletModel::prepareTransaction()
    switch(sendCoinsReturn.status)
    {
    case WalletModel::InvalidAddress:
        msgParams.first = tr("The recipient address is not valid. Please recheck.");
        break;
    case WalletModel::InvalidAmount:
        msgParams.first = tr("The amount to pay must be larger than 0.");
        break;
    case WalletModel::AmountExceedsBalance:
        msgParams.first = tr("The amount exceeds your balance.");
        break;
    case WalletModel::AmountWithFeeExceedsBalance:
        msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
        break;
    case WalletModel::DuplicateAddress:
        msgParams.first = tr("Duplicate address found: addresses should only be used once each.");
        break;
    case WalletModel::TransactionCreationFailed:
        msgParams.first = tr("Transaction creation failed!");
        msgParams.second = CClientUIInterface::MSG_ERROR;
        break;
    case WalletModel::TransactionCommitFailed:
        msgParams.first = tr("The transaction was rejected with the following reason: %1").arg(sendCoinsReturn.reasonCommitFailed);
        msgParams.second = CClientUIInterface::MSG_ERROR;
        break;
    case WalletModel::AbsurdFee:
        msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), maxTxFee));
        break;
    case WalletModel::PaymentRequestExpired:
        msgParams.first = tr("Payment request expired.");
        msgParams.second = CClientUIInterface::MSG_ERROR;
        break;
    // included to prevent a compiler warning.
    case WalletModel::OK:
    default:
        return;
    }

    Q_EMIT message(tr("Send Coins"), msgParams.first, msgParams.second);
}

void SendCoinsDialog::minimizeFeeSection(bool fMinimize)
{
    ui->labelFeeMinimized->setVisible(fMinimize);
    ui->buttonChooseFee  ->setVisible(fMinimize);
    ui->buttonMinimizeFee->setVisible(!fMinimize);
    ui->frameFeeSelection->setVisible(!fMinimize);
    ui->horizontalLayoutSmartFee->setContentsMargins(0, (fMinimize ? 0 : 6), 0, 0);
    fFeeMinimized = fMinimize;
}

void SendCoinsDialog::on_buttonChooseFee_clicked()
{
    minimizeFeeSection(false);
}

void SendCoinsDialog::on_buttonMinimizeFee_clicked()
{
    updateFeeMinimizedLabel();
    minimizeFeeSection(true);
}

void SendCoinsDialog::setMinimumFee()
{
    ui->radioCustomPerKilobyte->setChecked(true);
    ui->customFee->setValue(CWallet::GetRequiredFee(1000));
}

void SendCoinsDialog::updateFeeSectionControls()
{
    ui->sliderSmartFee          ->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->radioCustomAtLeast      ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() && CoinControlDialog::coinControl->HasSelected());
    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);

        // set nMinimumTotalFee to 0 to not accidentally pay a custom fee
        CoinControlDialog::coinControl->nMinimumTotalFee = 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());

        // if user has selected to set a minimum absolute fee, pass the value to coincontrol
        // set nMinimumTotalFee to 0 in case of user has selected that the fee is per KB
        CoinControlDialog::coinControl->nMinimumTotalFee = ui->radioCustomAtLeast->isChecked() ? ui->customFee->value() : 0;
    }
}

void SendCoinsDialog::updateFeeMinimizedLabel()
{
    if(!model || !model->getOptionsModel())
        return;
    if (ui->radioSmartFee->isChecked())
        ui->labelFeeMinimized->setText(ui->labelSmartFee->text());
    else {
        ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) +
            ((ui->radioCustomPerKilobyte->isChecked()) ? "/kB" : ""));
    }
}

void SendCoinsDialog::setAnonymizeMode(bool enableAnonymizeMode)
{
    fAnonymousMode = enableAnonymizeMode;

    if (fAnonymousMode) {
        ui->switchFundButton->setText(QString(tr("Use Transparent Balance")));
        ui->labelBalanceText->setText(QString(tr("Private Balance")));

        ui->checkBoxCoinControlChange->setEnabled(false);
        ui->lineEditCoinControlChange->setEnabled(false);

    } else {
        ui->switchFundButton->setText(QString(tr("Use Private Balance")));
        ui->labelBalanceText->setText(QString(tr("Transparent Balance")));

        ui->checkBoxCoinControlChange->setEnabled(true);
        if (ui->checkBoxCoinControlChange->isChecked()) {
            ui->lineEditCoinControlChange->setEnabled(true);
        }

    }

    if (model) {
        setBalance(model->getBalance(), 0, 0, 0, 0, 0, model->getLelantusModel()->getPrivateBalance().first, 0, 0);
    }
}

void SendCoinsDialog::removeUnmatchedOutput(CCoinControl &coinControl)
{
    std::vector<COutPoint> outpoints;
    coinControl.ListSelected(outpoints);

    for (auto const &out : outpoints) {
        auto it = pwalletMain->mapWallet.find(out.hash);
        if (it == pwalletMain->mapWallet.end()) {
            coinControl.UnSelect(out);
            continue;
        }

        auto isMint = it->second.tx->vout[out.n].scriptPubKey.IsMint();

        if (isMint != fAnonymousMode) {
            coinControl.UnSelect(out);
        }
    }
}

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")
        );
}

void SendCoinsDialog::updateSmartFeeLabel()
{
    if(!model || !model->getOptionsModel())
        return;

    int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
    int estimateFoundAtBlocks = nBlocksToConfirm;
    CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);
    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");
        ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
        ui->labelFeeEstimation->setText("");
        ui->fallbackFeeWarningLabel->setVisible(true);
        int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
        QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
        ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }");
        ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x"));
    }
    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).", "", estimateFoundAtBlocks));
        ui->fallbackFeeWarningLabel->setVisible(false);
    }

    updateFeeMinimizedLabel();
}

// Coin Control: copy label "Quantity" to clipboard
void SendCoinsDialog::coinControlClipboardQuantity()
{
    GUIUtil::setClipboard(ui->labelCoinControlQuantity->text());
}

// Coin Control: copy label "Amount" to clipboard
void SendCoinsDialog::coinControlClipboardAmount()
{
    GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));
}

// Coin Control: copy label "Fee" to clipboard
void SendCoinsDialog::coinControlClipboardFee()
{
    GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
}

// Coin Control: copy label "After fee" to clipboard
void SendCoinsDialog::coinControlClipboardAfterFee()
{
    GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
}

// Coin Control: copy label "Bytes" to clipboard
void SendCoinsDialog::coinControlClipboardBytes()
{
    GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
}

// Coin Control: copy label "Dust" to clipboard
void SendCoinsDialog::coinControlClipboardLowOutput()
{
    GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text());
}

// Coin Control: copy label "Change" to clipboard
void SendCoinsDialog::coinControlClipboardChange()
{
    GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
}

// Coin Control: settings menu - coin control enabled/disabled by user
void SendCoinsDialog::coinControlFeatureChanged(bool checked)
{
    ui->frameCoinControl->setVisible(checked);

    if (!checked && model) // coin control features disabled
        CoinControlDialog::coinControl->SetNull();

    // make sure we set back the confirmation target
    updateGlobalFeeVariables();
    coinControlUpdateLabels();
}

// Coin Control: button inputs -> show actual coin control dialog
void SendCoinsDialog::coinControlButtonClicked()
{
    CoinControlDialog dlg(fAnonymousMode, platformStyle);
    dlg.setModel(model);
    dlg.exec();
    coinControlUpdateLabels();
}

// Coin Control: checkbox custom change address
void SendCoinsDialog::coinControlChangeChecked(int state)
{
    if (state == Qt::Unchecked)
    {
        CoinControlDialog::coinControl->destChange = CNoDestination();
        ui->labelCoinControlChangeLabel->clear();
    }
    else
        // use this to re-validate an already entered address
        coinControlChangeEdited(ui->lineEditCoinControlChange->text());

    ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked));
}

// Coin Control: custom change address changed
void SendCoinsDialog::coinControlChangeEdited(const QString& text)
{
    if (model && model->getAddressTableModel())
    {
        // Default to no change address until verified
        CoinControlDialog::coinControl->destChange = CNoDestination();
        ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");

        CBitcoinAddress addr = CBitcoinAddress(text.toStdString());

        if (text.isEmpty()) // Nothing entered
        {
            ui->labelCoinControlChangeLabel->setText("");
        }
        else if (!addr.IsValid()) // Invalid address
        {
            ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Firo address"));
        }
        else // Valid address
        {
            CKeyID keyid;
            addr.GetKeyID(keyid);
            if (!model->havePrivKey(keyid)) // Unknown change address
            {
                ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));

                // confirmation dialog
                QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm custom change address"), tr("The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?"),
                    QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);

                if(btnRetVal == QMessageBox::Yes)
                    CoinControlDialog::coinControl->destChange = addr.Get();
                else
                {
                    ui->lineEditCoinControlChange->setText("");
                    ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");
                    ui->labelCoinControlChangeLabel->setText("");
                }
            }
            else // Known change address
            {
                ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");

                // Query label
                QString associatedLabel = model->getAddressTableModel()->labelForAddress(text);
                if (!associatedLabel.isEmpty())
                    ui->labelCoinControlChangeLabel->setText(associatedLabel);
                else
                    ui->labelCoinControlChangeLabel->setText(tr("(no label)"));

                CoinControlDialog::coinControl->destChange = addr.Get();
            }
        }
    }
}

// Coin Control: update labels
void SendCoinsDialog::coinControlUpdateLabels()
{
    if (!model || !model->getOptionsModel())
        return;

    if (model->getOptionsModel()->getCoinControlFeatures())
    {
        // enable minimum absolute fee UI controls
        ui->radioCustomAtLeast->setVisible(true);

        // only enable the feature if inputs are selected
        ui->radioCustomAtLeast->setEnabled(ui->radioCustomFee->isChecked()
            && !ui->checkBoxMinimumFee->isChecked()
            && CoinControlDialog::coinControl->HasSelected());
    }
    else
    {
        // in case coin control is disabled (=default), hide minimum absolute fee UI controls
        ui->radioCustomAtLeast->setVisible(false);
        return;
    }

    // set pay amounts
    CoinControlDialog::payAmounts.clear();
    CoinControlDialog::fSubtractFeeFromAmount = false;
    for(int i = 0; i < ui->entries->count(); ++i)
    {
        SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
        if(entry && !entry->isHidden())
        {
            SendCoinsRecipient rcp = entry->getValue();
            CoinControlDialog::payAmounts.append(rcp.amount);
            if (rcp.fSubtractFeeFromAmount)
                CoinControlDialog::fSubtractFeeFromAmount = true;
        }
    }

    if (CoinControlDialog::coinControl->HasSelected())
    {
        // actual coin control calculation
        CoinControlDialog::updateLabels(model, this, fAnonymousMode);

        // show coin control stats
        ui->labelCoinControlAutomaticallySelected->hide();
        ui->widgetCoinControl->show();
    }
    else
    {
        // hide coin control stats
        ui->labelCoinControlAutomaticallySelected->show();
        ui->widgetCoinControl->hide();
        ui->labelCoinControlInsuffFunds->hide();
    }
}

SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay,
    QWidget *parent) :
    QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)
{
    setDefaultButton(QMessageBox::Cancel);
    yesButton = button(QMessageBox::Yes);
    updateYesButton();
    connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown);
}

int SendConfirmationDialog::exec()
{
    updateYesButton();
    countDownTimer.start(1000);
    return QMessageBox::exec();
}

void SendConfirmationDialog::countDown()
{
    secDelay--;
    updateYesButton();

    if(secDelay <= 0)
    {
        countDownTimer.stop();
    }
}

void SendConfirmationDialog::updateYesButton()
{
    if(secDelay > 0)
    {
        yesButton->setEnabled(false);
        yesButton->setText(tr("Yes") + " (" + QString::number(secDelay) + ")");
    }
    else
    {
        yesButton->setEnabled(true);
        yesButton->setText(tr("Yes"));
    }
}

<MSG> Non-grammatical language improvements

<DFF> @@ -517,7 +517,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
         msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
         break;
     case WalletModel::DuplicateAddress:
-        msgParams.first = tr("Duplicate address found: can only send to each address once per send operation.");
+        msgParams.first = tr("Duplicate address found: addresses should only be used once each.");
         break;
     case WalletModel::TransactionCreationFailed:
         msgParams.first = tr("Transaction creation failed!");

{'commit': 'diff --git a/doc/gitian-building.md b/doc/gitian-building.md\nindex b9fbcb30a..1fa5b5f98 100644\n--- a/doc/gitian-building.md\n+++ b/doc/gitian-building.md\n@@ -393,4 +393,4 @@ Uploading signatures\n \n After building and signing you can push your signatures (both the `.assert` and `.assert.sig` files) to the\n [bitcoin/gitian.sigs](https://github.com/bitcoin/gitian.sigs/) repository, or if that\'s not possible create a pull\n-request. You can also mail the files to me (laanwj@gmail.com) and I\'ll commit them.\n+request. You can also mail the files to Wladimir (laanwj@gmail.com) and he will commit them.\ndiff --git a/doc/release-process.md b/doc/release-process.md\nindex 5dad9bf5d..cdcee0ec3 100644\n--- a/doc/release-process.md\n+++ b/doc/release-process.md\n@@ -164,4 +164,4 @@ Note: check that SHA256SUMS itself doesn\'t end up in SHA256SUMS, which is a spur\n \n - Add release notes for the new version to the directory `doc/release-notes` in git master\n \n-- Celebrate \n+- Celebrate\ndiff --git a/src/addrman.h b/src/addrman.h\nindex 98df370c7..b72dda49d 100644\n--- a/src/addrman.h\n+++ b/src/addrman.h\n@@ -105,7 +105,7 @@ public:\n /** Stochastic address manager\n  *\n  * Design goals:\n- *  * Keep the address tables in-memory, and asynchronously dump the entire to able in peers.dat.\n+ *  * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.\n  *  * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.\n  *\n  * To that end:\ndiff --git a/src/base58.h b/src/base58.h\nindex 8de90046a..787979c82 100644\n--- a/src/base58.h\n+++ b/src/base58.h\n@@ -6,10 +6,10 @@\n /**\n  * Why base-58 instead of standard base-64 encoding?\n  * - Don\'t want 0OIl characters that look the same in some fonts and\n- *      could be used to create visually identical looking account numbers.\n- * - A string with non-alphanumeric characters is not as easily accepted as an account number.\n+ *      could be used to create visually identical looking data.\n+ * - A string with non-alphanumeric characters is not as easily accepted as input.\n  * - E-mail usually won\'t line-break if there\'s no punctuation to break at.\n- * - Double-clicking selects the whole number as one word if it\'s all alphanumeric.\n+ * - Double-clicking selects the whole string as one word if it\'s all alphanumeric.\n  */\n #ifndef BITCOIN_BASE58_H\n #define BITCOIN_BASE58_H\ndiff --git a/src/chain.h b/src/chain.h\nindex 02f53cd2f..01be2d6e5 100644\n--- a/src/chain.h\n+++ b/src/chain.h\n@@ -74,7 +74,7 @@ enum BlockStatus {\n      */\n     BLOCK_VALID_TRANSACTIONS =    3,\n \n-    //! Outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30.\n+    //! Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends, BIP30.\n     //! Implies all parents are also at least CHAIN.\n     BLOCK_VALID_CHAIN        =    4,\n \ndiff --git a/src/chainparams.cpp b/src/chainparams.cpp\nindex 589c7b547..a9dd4c257 100644\n--- a/src/chainparams.cpp\n+++ b/src/chainparams.cpp\n@@ -112,7 +112,7 @@ public:\n         /** \n          * The message start string is designed to be unlikely to occur in normal data.\n          * The characters are rarely used upper ASCII, not valid as UTF-8, and produce\n-         * a large 4-byte int at any alignment.\n+         * a large 32-bit integer with any alignment.\n          */\n         pchMessageStart[0] = 0xf9;\n         pchMessageStart[1] = 0xbe;\n@@ -124,9 +124,10 @@ public:\n         nPruneAfterHeight = 100000;\n \n         /**\n-         * Build the genesis block. Note that the output of the genesis coinbase cannot\n-         * be spent as it did not originally exist in the database.\n-         * \n+         * Build the genesis block. Note that the output of its generation\n+         * transaction cannot be spent since it did not originally exist in the\n+         * database.\n+         *\n          * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)\n          *   CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)\n          *     CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)\ndiff --git a/src/chainparams.h b/src/chainparams.h\nindex 295133910..1b0390099 100644\n--- a/src/chainparams.h\n+++ b/src/chainparams.h\n@@ -56,7 +56,7 @@ public:\n     bool MiningRequiresPeers() const { return fMiningRequiresPeers; }\n     /** Default value for -checkmempool and -checkblockindex argument */\n     bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }\n-    /** Make standard checks */\n+    /** Policy: Filter transactions that do not match well-defined patterns */\n     bool RequireStandard() const { return fRequireStandard; }\n     int64_t PruneAfterHeight() const { return nPruneAfterHeight; }\n     /** Make miner stop after a block is found. In RPC, don\'t return until nGenProcLimit blocks are generated */\ndiff --git a/src/checkpoints.cpp b/src/checkpoints.cpp\nindex 71579bb30..e3d42c295 100644\n--- a/src/checkpoints.cpp\n+++ b/src/checkpoints.cpp\n@@ -15,9 +15,10 @@\n namespace Checkpoints {\n \n     /**\n-     * How many times we expect transactions after the last checkpoint to\n-     * be slower. This number is a compromise, as it can\'t be accurate for\n-     * every system. When reindexing from a fast disk with a slow CPU, it\n+     * How many times slower we expect checking transactions after the last\n+     * checkpoint to be (from checking signatures, which is skipped up to the\n+     * last checkpoint). This number is a compromise, as it can\'t be accurate\n+     * for every system. When reindexing from a fast disk with a slow CPU, it\n      * can be up to 20, while when downloading from a slow network with a\n      * fast multicore CPU, it won\'t be much higher than 1.\n      */\ndiff --git a/src/main.cpp b/src/main.cpp\nindex 263c2abf6..07156a9af 100644\n--- a/src/main.cpp\n+++ b/src/main.cpp\n@@ -142,8 +142,9 @@ namespace {\n     uint32_t nBlockSequenceId = 1;\n \n     /**\n-     * Sources of received blocks, to be able to send them reject messages or ban\n-     * them, if processing happens afterwards. Protected by cs_main.\n+     * Sources of received blocks, saved to be able to send them reject\n+     * messages or ban them when processing happens afterwards. Protected by\n+     * cs_main.\n      */\n     map<uint256, NodeId> mapBlockSource;\n \n@@ -389,7 +390,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl\n     }\n \n     // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor\n-    // of their current tip anymore. Go back enough to fix that.\n+    // of its current tip anymore. Go back enough to fix that.\n     state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock);\n     if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)\n         return;\n@@ -1721,7 +1722,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin\n     // already refuses previously-known transaction ids entirely.\n     // This rule was originally applied to all blocks with a timestamp after March 15, 2012, 0:00 UTC.\n     // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the\n-    // two in the chain that violate it. This prevents exploiting the issue against nodes in their\n+    // two in the chain that violate it. This prevents exploiting the issue against nodes during their\n     // initial block download.\n     bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don\'t have a hash.\n                           !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||\n@@ -2315,7 +2316,7 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) {\n     }\n \n     // The resulting new best tip may not be in setBlockIndexCandidates anymore, so\n-    // add them again.\n+    // add it again.\n     BlockMap::iterator it = mapBlockIndex.begin();\n     while (it != mapBlockIndex.end()) {\n         if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {\n@@ -3745,7 +3746,7 @@ void static ProcessGetData(CNode* pfrom)\n                             // no response\n                     }\n \n-                    // Trigger them to send a getblocks request for the next batch of inventory\n+                    // Trigger the peer node to send a getblocks request for the next batch of inventory\n                     if (inv.hash == pfrom->hashContinue)\n                     {\n                         // Bypass PushInventory, this must send even if redundant,\n@@ -4141,8 +4142,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,\n             pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));\n             if (--nLimit <= 0)\n             {\n-                // When this block is requested, we\'ll send an inv that\'ll make them\n-                // getblocks the next batch of inventory.\n+                // When this block is requested, we\'ll send an inv that\'ll\n+                // trigger the peer to getblocks the next batch of inventory.\n                 LogPrint("net", "  getblocks stopping at limit %d %s\\n", pindex->nHeight, pindex->GetBlockHash().ToString());\n                 pfrom->hashContinue = pindex->GetBlockHash();\n                 break;\n@@ -4379,9 +4380,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,\n \n     // This asymmetric behavior for inbound and outbound connections was introduced\n     // to prevent a fingerprinting attack: an attacker can send specific fake addresses\n-    // to users\' AddrMan and later request them by sending getaddr messages. \n-    // Making users (which are behind NAT and can only make outgoing connections) ignore \n-    // getaddr message mitigates the attack.\n+    // to users\' AddrMan and later request them by sending getaddr messages.\n+    // Making nodes which are behind NAT and can only make outgoing connections ignore\n+    // the getaddr message mitigates the attack.\n     else if ((strCommand == "getaddr") && (pfrom->fInbound))\n     {\n         pfrom->vAddrToSend.clear();\n@@ -4734,7 +4735,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)\n {\n     const Consensus::Params& consensusParams = Params().GetConsensus();\n     {\n-        // Don\'t send anything until we get their version message\n+        // Don\'t send anything until we get its version message\n         if (pto->nVersion == 0)\n             return true;\n \ndiff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp\nindex 1a931695e..7a33e3567 100644\n--- a/src/qt/sendcoinsdialog.cpp\n+++ b/src/qt/sendcoinsdialog.cpp\n@@ -517,7 +517,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn\n         msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);\n         break;\n     case WalletModel::DuplicateAddress:\n-        msgParams.first = tr("Duplicate address found: can only send to each address once per send operation.");\n+        msgParams.first = tr("Duplicate address found: addresses should only be used once each.");\n         break;\n     case WalletModel::TransactionCreationFailed:\n         msgParams.first = tr("Transaction creation failed!");\ndiff --git a/src/rpcserver.cpp b/src/rpcserver.cpp\nindex 61dda9125..12a5c4aef 100644\n--- a/src/rpcserver.cpp\n+++ b/src/rpcserver.cpp\n@@ -912,8 +912,8 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,\n     {\n         LogPrintf("ThreadRPCServer incorrect password attempt from %s\\n", conn->peer_address_to_string());\n         /* Deter brute-forcing\n-           If this results in a DoS the user really\n-           shouldn\'t have their RPC port exposed. */\n+           We don\'t support exposing the RPC port, so this shouldn\'t result\n+           in a DoS. */\n         MilliSleep(250);\n \n         conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;\n', 'commit_subject': 'Non-grammatical language improvements', 'repo_name': 'zcoinofficial/zcoin', 'committer': {'name': 'Luke Dashjr', 'email': 'd0b35c280567a6e00291dab426e321dcd3a56fd2@utopios.org', 'time_sec': '1430580239', 'tz_offset': '0', 'date': {'seconds': '1430580239'}}, 'commit_tree': 'da028bc52de857c1a89fb223ae8973859b1cf150', 'commit_message': 'Non-grammatical language improvements\n', 'language_name': 'HTML', 'license': 'mit', 'hunks': '@@ -517,7 +517,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn\n         msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);\n         break;\n     case WalletModel::DuplicateAddress:\n-        msgParams.first = tr("Duplicate address found: can only send to each address once per send operation.");\n+        msgParams.first = tr("Duplicate address found: addresses should only be used once each.");\n         break;\n     case WalletModel::TransactionCreationFailed:\n         msgParams.first = tr("Transaction creation failed!");\n', 'addition_count': 1, 'deletion_count': 1, 'src_file': 'a/src/qt/sendcoinsdialog.cpp', 'tgt_file': 'b/src/qt/sendcoinsdialog.cpp', 'file_extension': '.cpp', 'before_file': '// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include "sendcoinsdialog.h"\n#include "ui_sendcoinsdialog.h"\n\n#include "addresstablemodel.h"\n#include "bitcoinunits.h"\n#include "clientmodel.h"\n#include "coincontroldialog.h"\n#include "guiutil.h"\n#include "lelantusmodel.h"\n#include "optionsmodel.h"\n#include "platformstyle.h"\n#include "sendcoinsentry.h"\n#include "walletmodel.h"\n\n#include "base58.h"\n#include "chainparams.h"\n#include "lelantus.h"\n#include "wallet/coincontrol.h"\n#include "validation.h" // mempool and minRelayTxFee\n#include "ui_interface.h"\n#include "txmempool.h"\n#include "wallet/wallet.h"\n#include "sendtopcodedialog.h"\n#include "pcodemodel.h"\n\n#include <QFontMetrics>\n#include <QMessageBox>\n#include <QScrollBar>\n#include <QSettings>\n#include <QTextDocument>\n#include <QTimer>\n\n#define SEND_CONFIRM_DELAY   3\n\nSendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :\n    QDialog(parent),\n    ui(new Ui::SendCoinsDialog),\n    clientModel(0),\n    model(0),\n    fNewRecipientAllowed(true),\n    fFeeMinimized(true),\n    fAnonymousMode(true),\n    platformStyle(_platformStyle)\n{\n    ui->setupUi(this);\n\n    if (!_platformStyle->getImagesOnButtons()) {\n        ui->addButton->setIcon(QIcon());\n        ui->clearButton->setIcon(QIcon());\n        ui->sendButton->setIcon(QIcon());\n    } else {\n        ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add"));\n        ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));\n        ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send"));\n    }\n\n    GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);\n\n    addEntry();\n\n    connect(ui->addButton, &QPushButton::clicked, this, &SendCoinsDialog::addEntry);\n    connect(ui->clearButton, &QPushButton::clicked, this, &SendCoinsDialog::clear);\n    // Coin Control\n    connect(ui->pushButtonCoinControl, &QPushButton::clicked, this, &SendCoinsDialog::coinControlButtonClicked);\n    connect(ui->checkBoxCoinControlChange, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlChangeChecked);\n    connect(ui->lineEditCoinControlChange, &QValidatedLineEdit::textEdited, this, &SendCoinsDialog::coinControlChangeEdited);\n    // Coin Control: clipboard actions\n    QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);\n    QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);\n    QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);\n    QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);\n    QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);\n    QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);\n    QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);\n    connect(clipboardQuantityAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardQuantity);\n    connect(clipboardAmountAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAmount);\n    connect(clipboardFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardFee);\n    connect(clipboardAfterFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAfterFee);\n    connect(clipboardBytesAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardBytes);\n    connect(clipboardLowOutputAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardLowOutput);\n    connect(clipboardChangeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardChange);\n    ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);\n    ui->labelCoinControlAmount->addAction(clipboardAmountAction);\n    ui->labelCoinControlFee->addAction(clipboardFeeAction);\n    ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);\n    ui->labelCoinControlBytes->addAction(clipboardBytesAction);\n    ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);\n    ui->labelCoinControlChange->addAction(clipboardChangeAction);\n\n    ui->frameCoinControl->setAutoFillBackground(true);\n    ui->scrollArea->setAutoFillBackground(true);\n    ui->frameFee->setAutoFillBackground(true);\n\n    {\n        auto allowed = lelantus::IsLelantusAllowed();\n        setAnonymizeMode(allowed);\n\n        if (!allowed) {\n            ui->switchFundButton->setEnabled(false);\n        }\n    }\n\n    // init transaction fee section\n    QSettings settings;\n    if (!settings.contains("fFeeSectionMinimized"))\n        settings.setValue("fFeeSectionMinimized", true);\n    if (!settings.contains("nFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility\n        settings.setValue("nFeeRadio", 1); // custom\n    if (!settings.contains("nFeeRadio"))\n        settings.setValue("nFeeRadio", 0); // recommended\n    if (!settings.contains("nCustomFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility\n        settings.setValue("nCustomFeeRadio", 1); // total at least\n    if (!settings.contains("nCustomFeeRadio"))\n        settings.setValue("nCustomFeeRadio", 0); // per kilobyte\n    if (!settings.contains("nTransactionFee"))\n        settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE);\n    if (!settings.contains("fPayOnlyMinFee"))\n        settings.setValue("fPayOnlyMinFee", false);\n    ui->groupFee->setId(ui->radioSmartFee, 0);\n    ui->groupFee->setId(ui->radioCustomFee, 1);\n    ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);\n    ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0);\n    ui->groupCustomFee->setId(ui->radioCustomAtLeast, 1);\n    ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true);\n    ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());\n    ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());\n    minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());\n}\n\nvoid SendCoinsDialog::setClientModel(ClientModel *_clientModel)\n{\n    this->clientModel = _clientModel;\n\n    if (_clientModel)\n    {\n        connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateSmartFeeLabel);\n        connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateBlocks);\n    }\n}\n\nvoid SendCoinsDialog::setModel(WalletModel *_model)\n{\n    this->model = _model;\n\n    if(_model && _model->getOptionsModel())\n    {\n        for(int i = 0; i < ui->entries->count(); ++i)\n        {\n            SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());\n            if(entry)\n            {\n                entry->setModel(_model);\n            }\n        }\n\n        auto privateBalance = _model->getLelantusModel()->getPrivateBalance();\n\n        setBalance(\n            _model->getBalance(), _model->getUnconfirmedBalance(), _model->getImmatureBalance(),\n            _model->getWatchBalance(), _model->getWatchUnconfirmedBalance(), _model->getWatchImmatureBalance(),\n            privateBalance.first, privateBalance.second, _model->getAnonymizableBalance());\n\n        connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance);\n        connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::updateDisplayUnit);\n        updateDisplayUnit();\n\n        // Coin Control\n        connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::coinControlUpdateLabels);\n        connect(_model->getOptionsModel(), &OptionsModel::coinControlFeaturesChanged, this, &SendCoinsDialog::coinControlFeatureChanged);\n        ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures());\n        coinControlUpdateLabels();\n\n        // fee section\n        connect(ui->sliderSmartFee, &QSlider::valueChanged, this, &SendCoinsDialog::updateSmartFeeLabel);\n        connect(ui->sliderSmartFee, &QSlider::valueChanged, this, &SendCoinsDialog::updateGlobalFeeVariables);\n        connect(ui->sliderSmartFee, &QSlider::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);\n        connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls);\n        connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateGlobalFeeVariables);\n        connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);\n        connect(ui->groupCustomFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateGlobalFeeVariables);\n        connect(ui->groupCustomFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);\n        connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::updateGlobalFeeVariables);\n        connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);\n        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::setMinimumFee);\n        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateFeeSectionControls);\n        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateGlobalFeeVariables);\n        connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels);\n        ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));\n        updateFeeSectionControls();\n        updateMinFeeLabel();\n        updateSmartFeeLabel();\n        updateGlobalFeeVariables();\n\n        // set the smartfee-sliders default value (wallets default conf.target or last stored value)\n        QSettings settings;\n        if (settings.value("nSmartFeeSliderPosition").toInt() == 0)\n            ui->sliderSmartFee->setValue(ui->sliderSmartFee->maximum() - model->getDefaultConfirmTarget() + 2);\n        else\n            ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());\n    }\n}\n\nSendCoinsDialog::~SendCoinsDialog()\n{\n    QSettings settings;\n    settings.setValue("fFeeSectionMinimized", fFeeMinimized);\n    settings.setValue("nFeeRadio", true);\n    settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId());\n    settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value());\n    settings.setValue("nTransactionFee", (qint64)ui->customFee->value());\n    settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());\n\n    delete ui;\n}\n\nvoid SendCoinsDialog::on_sendButton_clicked()\n{\n    updateGlobalFeeVariables();\n\n    if(!model || !model->getOptionsModel())\n        return;\n\n    QList<SendCoinsRecipient> recipients;\n    bool valid = true;\n\n    using UnlockContext = WalletModel::UnlockContext;\n    std::unique_ptr<UnlockContext> ctx;\n\n    for(int i = 0; i < ui->entries->count(); ++i)\n    {\n        SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());\n        if(entry)\n        {\n            if(entry->validate())\n            {\n                SendCoinsRecipient recipient = entry->getValue();\n                if(entry->isPayToPcode()) {\n                    if (!model->getPcodeModel()) return;\n                    std::unique_ptr<SendtoPcodeDialog> dialog(new SendtoPcodeDialog(this, recipient.address.toStdString(), recipient.label.toStdString()));\n                    dialog->setModel(model);\n                    dialog->exec();\n                    std::pair<SendtoPcodeDialog::Result, CBitcoinAddress> const sendResult = dialog->getResult();\n                    switch (sendResult.first) {\n                        case SendtoPcodeDialog::Result::addressSelected:\n                            recipient.address = sendResult.second.ToString().c_str();\n                            break;\n                        default:\n                            return;\n                    }\n                    ctx = dialog->getUnlockContext();\n                }\n                recipients.append(recipient);\n            }\n            else\n            {\n                valid = false;\n            }\n        }\n    }\n\n    if(!valid || recipients.isEmpty())\n    {\n        return;\n    }\n\n    fNewRecipientAllowed = false;\n    if(!ctx)\n    {\n        ctx = std::unique_ptr<UnlockContext>(new UnlockContext(model->requestUnlock()));\n    }\n    if(!ctx->isValid())\n    {\n        // Unlock wallet was cancelled\n        fNewRecipientAllowed = true;\n        return;\n    }\n\n    // prepare transaction for getting txFee earlier\n    WalletModelTransaction currentTransaction(recipients);\n    WalletModel::SendCoinsReturn prepareStatus;\n\n    // Always use a CCoinControl instance, use the CoinControlDialog instance if CoinControl has been enabled\n    CCoinControl ctrl;\n    if (model->getOptionsModel()->getCoinControlFeatures()) {\n        ctrl = *CoinControlDialog::coinControl;\n        removeUnmatchedOutput(ctrl);\n    }\n    if (ui->radioSmartFee->isChecked())\n        ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;\n    else\n        ctrl.nConfirmTarget = 0;\n\n    if (fAnonymousMode) {\n        prepareStatus = model->prepareJoinSplitTransaction(currentTransaction, &ctrl);\n    } else {\n        prepareStatus = model->prepareTransaction(currentTransaction, &ctrl);\n    }\n\n    // process prepareStatus and on error generate message shown to user\n    processSendCoinsReturn(prepareStatus,\n        BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee()));\n\n    if(prepareStatus.status != WalletModel::OK) {\n        fNewRecipientAllowed = true;\n        return;\n    }\n\n    CAmount txFee = currentTransaction.getTransactionFee();\n\n    // Format confirmation message\n    QStringList formatted;\n    Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients())\n    {\n        // generate bold amount string\n        QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);\n        amount.append("</b>");\n        // generate monospace address string\n        QString address = "<span style=\'font-family: monospace;\'>" + rcp.address;\n        address.append("</span>");\n\n        QString recipientElement;\n\n        if (!rcp.paymentRequest.IsInitialized()) // normal payment\n        {\n            if(rcp.label.length() > 0) // label with address\n            {\n                recipientElement = tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.label));\n                recipientElement.append(QString(" (%1)").arg(address));\n            }\n            else // just address\n            {\n                recipientElement = tr("%1 to %2").arg(amount, address);\n            }\n        }\n        else if(!rcp.authenticatedMerchant.isEmpty()) // authenticated payment request\n        {\n            recipientElement = tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.authenticatedMerchant));\n        }\n        else // unauthenticated payment request\n        {\n            recipientElement = tr("%1 to %2").arg(amount, address);\n        }\n\n        formatted.append(recipientElement);\n    }\n\n    QString questionString = tr("Are you sure you want to send?");\n    questionString.append("<br /><br />%1");\n\n    if(txFee > 0)\n    {\n        // append fee string if a fee is required\n        questionString.append("<hr /><span style=\'color:#aa0000;\'>");\n        questionString.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));\n        questionString.append("</span> ");\n        questionString.append(tr("added as transaction fee"));\n\n        // append transaction size\n        questionString.append(" (" + QString::number((double)currentTransaction.getTransactionSize() / 1000) + " kB)");\n    }\n\n    // add total amount in all subdivision units\n    questionString.append("<hr />");\n    CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee;\n    QStringList alternativeUnits;\n    Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())\n    {\n        if(u != model->getOptionsModel()->getDisplayUnit())\n            alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));\n    }\n    questionString.append(tr("Total Amount %1")\n        .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount)));\n    questionString.append(QString("<span style=\'font-size:10pt;font-weight:normal;\'><br />(=%2)</span>")\n        .arg(alternativeUnits.join(" " + tr("or") + "<br />")));\n\n    SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),\n        questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);\n    confirmationDialog.exec();\n    QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();\n\n    if(retval != QMessageBox::Yes)\n    {\n        fNewRecipientAllowed = true;\n        return;\n    }\n\n    // now send the prepared transaction\n    WalletModel::SendCoinsReturn sendStatus;\n\n    if (fAnonymousMode) {\n        sendStatus = model->sendPrivateCoins(currentTransaction);\n    } else {\n        sendStatus = model->sendCoins(currentTransaction);\n    }\n    // process sendStatus and on error generate message shown to user\n    processSendCoinsReturn(sendStatus);\n\n    if (sendStatus.status == WalletModel::OK)\n    {\n        for(int i = 0; i < ui->entries->count(); ++i)\n        {\n            SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());\n            if(entry && entry->isPayToPcode())\n            {\n                SendCoinsRecipient recipient = entry->getValue();\n                model->getPcodeModel()->generateTheirNextAddress(recipient.address.toStdString());\n            }\n        }\n        accept();\n        CoinControlDialog::coinControl->UnSelectAll();\n        coinControlUpdateLabels();\n    }\n    fNewRecipientAllowed = true;\n}\n\nvoid SendCoinsDialog::on_switchFundButton_clicked()\n{\n    setAnonymizeMode(!fAnonymousMode);\n    coinControlUpdateLabels();\n}\n\nvoid SendCoinsDialog::clear()\n{\n    // Remove entries until only one left\n    while(ui->entries->count())\n    {\n        ui->entries->takeAt(0)->widget()->deleteLater();\n    }\n    addEntry();\n\n    updateTabsAndLabels();\n}\n\nvoid SendCoinsDialog::reject()\n{\n    clear();\n}\n\nvoid SendCoinsDialog::accept()\n{\n    clear();\n}\n\nSendCoinsEntry *SendCoinsDialog::addEntry()\n{\n    SendCoinsEntry *entry = new SendCoinsEntry(platformStyle, this);\n    entry->setModel(model);\n    ui->entries->addWidget(entry);\n    connect(entry, &SendCoinsEntry::removeEntry, this, &SendCoinsDialog::removeEntry);\n    connect(entry, &SendCoinsEntry::payAmountChanged, this, &SendCoinsDialog::coinControlUpdateLabels);\n    connect(entry, &SendCoinsEntry::subtractFeeFromAmountChanged, this, &SendCoinsDialog::coinControlUpdateLabels);\n\n    // Focus the field, so that entry can start immediately\n    entry->clear();\n    entry->setFocus();\n    ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());\n    qApp->processEvents();\n    QScrollBar* bar = ui->scrollArea->verticalScrollBar();\n    if(bar)\n        bar->setSliderPosition(bar->maximum());\n\n    updateTabsAndLabels();\n    return entry;\n}\n\nvoid SendCoinsDialog::updateBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)\n{\n    if (header)\n    {\n        return;\n    }\n\n    auto allowed = lelantus::IsLelantusAllowed(count);\n\n    if (allowed && !ui->switchFundButton->isEnabled())\n    {\n        setAnonymizeMode(true);\n        ui->switchFundButton->setEnabled(true);\n    }\n    else if (!allowed && ui->switchFundButton->isEnabled())\n    {\n        setAnonymizeMode(false);\n        ui->switchFundButton->setEnabled(false);\n    }\n}\n\nvoid SendCoinsDialog::updateTabsAndLabels()\n{\n    setupTabChain(0);\n    coinControlUpdateLabels();\n}\n\nvoid SendCoinsDialog::removeEntry(SendCoinsEntry* entry)\n{\n    entry->hide();\n\n    // If the last entry is about to be removed add an empty one\n    if (ui->entries->count() == 1)\n        addEntry();\n\n    entry->deleteLater();\n\n    updateTabsAndLabels();\n}\n\nQWidget *SendCoinsDialog::setupTabChain(QWidget *prev)\n{\n    for(int i = 0; i < ui->entries->count(); ++i)\n    {\n        SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());\n        if(entry)\n        {\n        msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);\n        break;\n    case WalletModel::DuplicateAddress:\n        msgParams.first = tr("Duplicate address found: can only send to each address once per send operation.");\n        break;\n    case WalletModel::TransactionCreationFailed:\n        msgParams.first = tr("Transaction creation failed!");\n}\n\nvoid SendCoinsDialog::setAddress(const QString &address)\n{\n    SendCoinsEntry *entry = 0;\n    // Replace the first entry if it is still unused\n    if(ui->entries->count() == 1)\n    {\n        SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());\n        if(first->isClear())\n        {\n            entry = first;\n        }\n    }\n    if(!entry)\n    {\n        entry = addEntry();\n    }\n\n    entry->setAddress(address);\n}\n\nvoid SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)\n{\n    if(!fNewRecipientAllowed)\n        return;\n\n    SendCoinsEntry *entry = 0;\n    // Replace the first entry if it is still unused\n    if(ui->entries->count() == 1)\n    {\n        SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());\n        if(first->isClear())\n        {\n            entry = first;\n        }\n    }\n    if(!entry)\n    {\n        entry = addEntry();\n    }\n\n    entry->setValue(rv);\n    updateTabsAndLabels();\n}\n\nbool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)\n{\n    // Just paste the entry, all pre-checks\n    // are done in paymentserver.cpp.\n    pasteEntry(rv);\n    return true;\n}\n\nvoid SendCoinsDialog::setBalance(\n    const CAmount& balance,\n    const CAmount& unconfirmedBalance,\n    const CAmount& immatureBalance,\n    const CAmount& watchBalance,\n    const CAmount& watchUnconfirmedBalance,\n    const CAmount& watchImmatureBalance,\n    const CAmount& privateBalance,\n    const CAmount& unconfirmedPrivateBalance,\n    const CAmount& anonymizableBalance)\n{\n    Q_UNUSED(unconfirmedBalance);\n    Q_UNUSED(immatureBalance);\n    Q_UNUSED(watchBalance);\n    Q_UNUSED(watchUnconfirmedBalance);\n    Q_UNUSED(watchImmatureBalance);\n    Q_UNUSED(unconfirmedPrivateBalance);\n    Q_UNUSED(anonymizableBalance);\n\n    if(model && model->getOptionsModel())\n    {\n        ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),\n            fAnonymousMode ? privateBalance : balance));\n    }\n}\n\nvoid SendCoinsDialog::updateDisplayUnit()\n{\n    setBalance(model->getBalance(), 0, 0, 0, 0, 0, model->getLelantusModel()->getPrivateBalance().first, 0, 0);\n    ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());\n    updateMinFeeLabel();\n    updateSmartFeeLabel();\n}\n\nvoid SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg)\n{\n    QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;\n    // Default to a warning message, override if error message is needed\n    msgParams.second = CClientUIInterface::MSG_WARNING;\n\n    // This comment is specific to SendCoinsDialog usage of WalletModel::SendCoinsReturn.\n    // WalletModel::TransactionCommitFailed is used only in WalletModel::sendCoins()\n    // all others are used only in WalletModel::prepareTransaction()\n    switch(sendCoinsReturn.status)\n    {\n    case WalletModel::InvalidAddress:\n        msgParams.first = tr("The recipient address is not valid. Please recheck.");\n        break;\n    case WalletModel::InvalidAmount:\n        msgParams.first = tr("The amount to pay must be larger than 0.");\n        break;\n    case WalletModel::AmountExceedsBalance:\n        msgParams.first = tr("The amount exceeds your balance.");\n        break;\n    case WalletModel::AmountWithFeeExceedsBalance:\n        msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);\n        break;\n    case WalletModel::DuplicateAddress:\n        msgParams.first = tr("Duplicate address found: addresses should only be used once each.");\n        break;\n    case WalletModel::TransactionCreationFailed:\n        msgParams.first = tr("Transaction creation failed!");\n        msgParams.second = CClientUIInterface::MSG_ERROR;\n        break;\n    case WalletModel::TransactionCommitFailed:\n        msgParams.first = tr("The transaction was rejected with the following reason: %1").arg(sendCoinsReturn.reasonCommitFailed);\n        msgParams.second = CClientUIInterface::MSG_ERROR;\n        break;\n    case WalletModel::AbsurdFee:\n        msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), maxTxFee));\n        break;\n    case WalletModel::PaymentRequestExpired:\n        msgParams.first = tr("Payment request expired.");\n        msgParams.second = CClientUIInterface::MSG_ERROR;\n        break;\n    // included to prevent a compiler warning.\n    case WalletModel::OK:\n    default:\n        return;\n    }\n\n    Q_EMIT message(tr("Send Coins"), msgParams.first, msgParams.second);\n}\n\nvoid SendCoinsDialog::minimizeFeeSection(bool fMinimize)\n{\n    ui->labelFeeMinimized->setVisible(fMinimize);\n    ui->buttonChooseFee  ->setVisible(fMinimize);\n    ui->buttonMinimizeFee->setVisible(!fMinimize);\n    ui->frameFeeSelection->setVisible(!fMinimize);\n    ui->horizontalLayoutSmartFee->setContentsMargins(0, (fMinimize ? 0 : 6), 0, 0);\n    fFeeMinimized = fMinimize;\n}\n\nvoid SendCoinsDialog::on_buttonChooseFee_clicked()\n{\n    minimizeFeeSection(false);\n}\n\nvoid SendCoinsDialog::on_buttonMinimizeFee_clicked()\n{\n    updateFeeMinimizedLabel();\n    minimizeFeeSection(true);\n}\n\nvoid SendCoinsDialog::setMinimumFee()\n{\n    ui->radioCustomPerKilobyte->setChecked(true);\n    ui->customFee->setValue(CWallet::GetRequiredFee(1000));\n}\n\nvoid SendCoinsDialog::updateFeeSectionControls()\n{\n    ui->sliderSmartFee          ->setEnabled(ui->radioSmartFee->isChecked());\n    ui->labelSmartFee           ->setEnabled(ui->radioSmartFee->isChecked());\n    ui->labelSmartFee2          ->setEnabled(ui->radioSmartFee->isChecked());\n    ui->labelSmartFee3          ->setEnabled(ui->radioSmartFee->isChecked());\n    ui->labelFeeEstimation      ->setEnabled(ui->radioSmartFee->isChecked());\n    ui->labelSmartFeeNormal     ->setEnabled(ui->radioSmartFee->isChecked());\n    ui->labelSmartFeeFast       ->setEnabled(ui->radioSmartFee->isChecked());\n\n    ui->confirmationTargetLabel ->setEnabled(ui->radioSmartFee->isChecked());\n    ui->checkBoxMinimumFee      ->setEnabled(ui->radioCustomFee->isChecked());\n    ui->labelMinFeeWarning      ->setEnabled(ui->radioCustomFee->isChecked());\n    ui->radioCustomPerKilobyte  ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());\n    ui->radioCustomAtLeast      ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() && CoinControlDialog::coinControl->HasSelected());\n    ui->customFee               ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());\n}\n\nvoid SendCoinsDialog::updateGlobalFeeVariables()\n{\n    if (ui->radioSmartFee->isChecked())\n    {\n        int nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;\n        payTxFee = CFeeRate(0);\n\n        // set nMinimumTotalFee to 0 to not accidentally pay a custom fee\n        CoinControlDialog::coinControl->nMinimumTotalFee = 0;\n\n        // show the estimated required time for confirmation\n        ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget * Params().GetConsensus().nPowTargetSpacing) + " / " + tr("%n block(s)", "", nConfirmTarget));\n    }\n    else\n    {\n        payTxFee = CFeeRate(ui->customFee->value());\n\n        // if user has selected to set a minimum absolute fee, pass the value to coincontrol\n        // set nMinimumTotalFee to 0 in case of user has selected that the fee is per KB\n        CoinControlDialog::coinControl->nMinimumTotalFee = ui->radioCustomAtLeast->isChecked() ? ui->customFee->value() : 0;\n    }\n}\n\nvoid SendCoinsDialog::updateFeeMinimizedLabel()\n{\n    if(!model || !model->getOptionsModel())\n        return;\n    if (ui->radioSmartFee->isChecked())\n        ui->labelFeeMinimized->setText(ui->labelSmartFee->text());\n    else {\n        ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) +\n            ((ui->radioCustomPerKilobyte->isChecked()) ? "/kB" : ""));\n    }\n}\n\nvoid SendCoinsDialog::setAnonymizeMode(bool enableAnonymizeMode)\n{\n    fAnonymousMode = enableAnonymizeMode;\n\n    if (fAnonymousMode) {\n        ui->switchFundButton->setText(QString(tr("Use Transparent Balance")));\n        ui->labelBalanceText->setText(QString(tr("Private Balance")));\n\n        ui->checkBoxCoinControlChange->setEnabled(false);\n        ui->lineEditCoinControlChange->setEnabled(false);\n\n    } else {\n        ui->switchFundButton->setText(QString(tr("Use Private Balance")));\n        ui->labelBalanceText->setText(QString(tr("Transparent Balance")));\n\n        ui->checkBoxCoinControlChange->setEnabled(true);\n        if (ui->checkBoxCoinControlChange->isChecked()) {\n            ui->lineEditCoinControlChange->setEnabled(true);\n        }\n\n    }\n\n    if (model) {\n        setBalance(model->getBalance(), 0, 0, 0, 0, 0, model->getLelantusModel()->getPrivateBalance().first, 0, 0);\n    }\n}\n\nvoid SendCoinsDialog::removeUnmatchedOutput(CCoinControl &coinControl)\n{\n    std::vector<COutPoint> outpoints;\n    coinControl.ListSelected(outpoints);\n\n    for (auto const &out : outpoints) {\n        auto it = pwalletMain->mapWallet.find(out.hash);\n        if (it == pwalletMain->mapWallet.end()) {\n            coinControl.UnSelect(out);\n            continue;\n        }\n\n        auto isMint = it->second.tx->vout[out.n].scriptPubKey.IsMint();\n\n        if (isMint != fAnonymousMode) {\n            coinControl.UnSelect(out);\n        }\n    }\n}\n\nvoid SendCoinsDialog::updateMinFeeLabel()\n{\n    if (model && model->getOptionsModel())\n        ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(\n            BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB")\n        );\n}\n\nvoid SendCoinsDialog::updateSmartFeeLabel()\n{\n    if(!model || !model->getOptionsModel())\n        return;\n\n    int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;\n    int estimateFoundAtBlocks = nBlocksToConfirm;\n    CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);\n    if (feeRate <= CFeeRate(0)) // not enough data => minfee\n    {\n        ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(\n            model->getOptionsModel()->getDisplayUnit(),\n            std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");\n        ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)\n        ui->labelFeeEstimation->setText("");\n        ui->fallbackFeeWarningLabel->setVisible(true);\n        int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();\n        QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));\n        ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }");\n        ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x"));\n    }\n    else\n    {\n        ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),\n                                                                std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");\n        ui->labelSmartFee2->hide();\n        ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks));\n        ui->fallbackFeeWarningLabel->setVisible(false);\n    }\n\n    updateFeeMinimizedLabel();\n}\n\n// Coin Control: copy label "Quantity" to clipboard\nvoid SendCoinsDialog::coinControlClipboardQuantity()\n{\n    GUIUtil::setClipboard(ui->labelCoinControlQuantity->text());\n}\n\n// Coin Control: copy label "Amount" to clipboard\nvoid SendCoinsDialog::coinControlClipboardAmount()\n{\n    GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));\n}\n\n// Coin Control: copy label "Fee" to clipboard\nvoid SendCoinsDialog::coinControlClipboardFee()\n{\n    GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));\n}\n\n// Coin Control: copy label "After fee" to clipboard\nvoid SendCoinsDialog::coinControlClipboardAfterFee()\n{\n    GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));\n}\n\n// Coin Control: copy label "Bytes" to clipboard\nvoid SendCoinsDialog::coinControlClipboardBytes()\n{\n    GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));\n}\n\n// Coin Control: copy label "Dust" to clipboard\nvoid SendCoinsDialog::coinControlClipboardLowOutput()\n{\n    GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text());\n}\n\n// Coin Control: copy label "Change" to clipboard\nvoid SendCoinsDialog::coinControlClipboardChange()\n{\n    GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, ""));\n}\n\n// Coin Control: settings menu - coin control enabled/disabled by user\nvoid SendCoinsDialog::coinControlFeatureChanged(bool checked)\n{\n    ui->frameCoinControl->setVisible(checked);\n\n    if (!checked && model) // coin control features disabled\n        CoinControlDialog::coinControl->SetNull();\n\n    // make sure we set back the confirmation target\n    updateGlobalFeeVariables();\n    coinControlUpdateLabels();\n}\n\n// Coin Control: button inputs -> show actual coin control dialog\nvoid SendCoinsDialog::coinControlButtonClicked()\n{\n    CoinControlDialog dlg(fAnonymousMode, platformStyle);\n    dlg.setModel(model);\n    dlg.exec();\n    coinControlUpdateLabels();\n}\n\n// Coin Control: checkbox custom change address\nvoid SendCoinsDialog::coinControlChangeChecked(int state)\n{\n    if (state == Qt::Unchecked)\n    {\n        CoinControlDialog::coinControl->destChange = CNoDestination();\n        ui->labelCoinControlChangeLabel->clear();\n    }\n    else\n        // use this to re-validate an already entered address\n        coinControlChangeEdited(ui->lineEditCoinControlChange->text());\n\n    ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked));\n}\n\n// Coin Control: custom change address changed\nvoid SendCoinsDialog::coinControlChangeEdited(const QString& text)\n{\n    if (model && model->getAddressTableModel())\n    {\n        // Default to no change address until verified\n        CoinControlDialog::coinControl->destChange = CNoDestination();\n        ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");\n\n        CBitcoinAddress addr = CBitcoinAddress(text.toStdString());\n\n        if (text.isEmpty()) // Nothing entered\n        {\n            ui->labelCoinControlChangeLabel->setText("");\n        }\n        else if (!addr.IsValid()) // Invalid address\n        {\n            ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Firo address"));\n        }\n        else // Valid address\n        {\n            CKeyID keyid;\n            addr.GetKeyID(keyid);\n            if (!model->havePrivKey(keyid)) // Unknown change address\n            {\n                ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));\n\n                // confirmation dialog\n                QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm custom change address"), tr("The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?"),\n                    QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);\n\n                if(btnRetVal == QMessageBox::Yes)\n                    CoinControlDialog::coinControl->destChange = addr.Get();\n                else\n                {\n                    ui->lineEditCoinControlChange->setText("");\n                    ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");\n                    ui->labelCoinControlChangeLabel->setText("");\n                }\n            }\n            else // Known change address\n            {\n                ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");\n\n                // Query label\n                QString associatedLabel = model->getAddressTableModel()->labelForAddress(text);\n                if (!associatedLabel.isEmpty())\n                    ui->labelCoinControlChangeLabel->setText(associatedLabel);\n                else\n                    ui->labelCoinControlChangeLabel->setText(tr("(no label)"));\n\n                CoinControlDialog::coinControl->destChange = addr.Get();\n            }\n        }\n    }\n}\n\n// Coin Control: update labels\nvoid SendCoinsDialog::coinControlUpdateLabels()\n{\n    if (!model || !model->getOptionsModel())\n        return;\n\n    if (model->getOptionsModel()->getCoinControlFeatures())\n    {\n        // enable minimum absolute fee UI controls\n        ui->radioCustomAtLeast->setVisible(true);\n\n        // only enable the feature if inputs are selected\n        ui->radioCustomAtLeast->setEnabled(ui->radioCustomFee->isChecked()\n            && !ui->checkBoxMinimumFee->isChecked()\n            && CoinControlDialog::coinControl->HasSelected());\n    }\n    else\n    {\n        // in case coin control is disabled (=default), hide minimum absolute fee UI controls\n        ui->radioCustomAtLeast->setVisible(false);\n        return;\n    }\n\n    // set pay amounts\n    CoinControlDialog::payAmounts.clear();\n    CoinControlDialog::fSubtractFeeFromAmount = false;\n    for(int i = 0; i < ui->entries->count(); ++i)\n    {\n        SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());\n        if(entry && !entry->isHidden())\n        {\n            SendCoinsRecipient rcp = entry->getValue();\n            CoinControlDialog::payAmounts.append(rcp.amount);\n            if (rcp.fSubtractFeeFromAmount)\n                CoinControlDialog::fSubtractFeeFromAmount = true;\n        }\n    }\n\n    if (CoinControlDialog::coinControl->HasSelected())\n    {\n        // actual coin control calculation\n        CoinControlDialog::updateLabels(model, this, fAnonymousMode);\n\n        // show coin control stats\n        ui->labelCoinControlAutomaticallySelected->hide();\n        ui->widgetCoinControl->show();\n    }\n    else\n    {\n        // hide coin control stats\n        ui->labelCoinControlAutomaticallySelected->show();\n        ui->widgetCoinControl->hide();\n        ui->labelCoinControlInsuffFunds->hide();\n    }\n}\n\nSendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay,\n    QWidget *parent) :\n    QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)\n{\n    setDefaultButton(QMessageBox::Cancel);\n    yesButton = button(QMessageBox::Yes);\n    updateYesButton();\n    connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown);\n}\n\nint SendConfirmationDialog::exec()\n{\n    updateYesButton();\n    countDownTimer.start(1000);\n    return QMessageBox::exec();\n}\n\nvoid SendConfirmationDialog::countDown()\n{\n    secDelay--;\n    updateYesButton();\n\n    if(secDelay <= 0)\n    {\n        countDownTimer.stop();\n    }\n}\n\nvoid SendConfirmationDialog::updateYesButton()\n{\n    if(secDelay > 0)\n    {\n        yesButton->setEnabled(false);\n        yesButton->setText(tr("Yes") + " (" + QString::number(secDelay) + ")");\n    }\n    else\n    {\n        yesButton->setEnabled(true);\n        yesButton->setText(tr("Yes"));\n    }\n}\n', 'message': 'Non-grammatical language improvements\n', 'author_name': 'Luke Dashjr', 'lang': 'cpp'}