Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <bitcoin-build-config.h> // IWYU pragma: keep7#include <qt/sendcoinsdialog.h>8#include <qt/forms/ui_sendcoinsdialog.h>10#include <qt/addresstablemodel.h>11#include <qt/bitcoinunits.h>12#include <qt/clientmodel.h>13#include <qt/coincontroldialog.h>14#include <qt/guiutil.h>15#include <qt/optionsmodel.h>16#include <qt/platformstyle.h>17#include <qt/sendcoinsentry.h>19#include <chainparams.h>20#include <interfaces/node.h>21#include <key_io.h>22#include <node/interface_ui.h>23#include <node/types.h>24#include <txmempool.h>25#include <validation.h>26#include <wallet/coincontrol.h>27#include <wallet/fees.h>28#include <wallet/types.h>29#include <wallet/wallet.h>31#include <array>32#include <chrono>33#include <fstream>34#include <memory>35#include <optional>37#include <QFontMetrics>38#include <QScrollBar>39#include <QSettings>40#include <QTextDocument>42using common::PSBTError;43using wallet::CCoinControl;45static constexpr std::array confTargets{2, 4, 6, 12, 24, 48, 144, 504, 1008};46int getConfTargetForIndex(int index) {47if (index+1 > static_cast<int>(confTargets.size())) {48return confTargets.back();49}50if (index < 0) {51return confTargets[0];52}53return confTargets[index];54}55int getIndexForConfTarget(int target) {56for (unsigned int i = 0; i < confTargets.size(); i++) {57if (confTargets[i] >= target) {58return i;59}60}61return confTargets.size() - 1;62}64SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :65QDialog(parent, GUIUtil::dialog_flags),66ui(new Ui::SendCoinsDialog),67m_coin_control(new CCoinControl),68platformStyle(_platformStyle)69{70ui->setupUi(this);72if (!_platformStyle->getImagesOnButtons()) {73ui->addButton->setIcon(QIcon());74ui->clearButton->setIcon(QIcon());75ui->sendButton->setIcon(QIcon());76} else {77ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add"));78ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));79ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send"));80}82GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);84addEntry();86connect(ui->addButton, &QPushButton::clicked, this, &SendCoinsDialog::addEntry);87connect(ui->clearButton, &QPushButton::clicked, this, &SendCoinsDialog::clear);89// Coin Control90connect(ui->pushButtonCoinControl, &QPushButton::clicked, this, &SendCoinsDialog::coinControlButtonClicked);91#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))92connect(ui->checkBoxCoinControlChange, &QCheckBox::checkStateChanged, this, &SendCoinsDialog::coinControlChangeChecked);93#else94connect(ui->checkBoxCoinControlChange, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlChangeChecked);95#endif96connect(ui->lineEditCoinControlChange, &QValidatedLineEdit::textEdited, this, &SendCoinsDialog::coinControlChangeEdited);98// Coin Control: clipboard actions99QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);100QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);101QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);102QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);103QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);104QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);105connect(clipboardQuantityAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardQuantity);106connect(clipboardAmountAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAmount);107connect(clipboardFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardFee);108connect(clipboardAfterFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAfterFee);109connect(clipboardBytesAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardBytes);110connect(clipboardChangeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardChange);111ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);112ui->labelCoinControlAmount->addAction(clipboardAmountAction);113ui->labelCoinControlFee->addAction(clipboardFeeAction);114ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);115ui->labelCoinControlBytes->addAction(clipboardBytesAction);116ui->labelCoinControlChange->addAction(clipboardChangeAction);118// init transaction fee section119QSettings settings;120if (!settings.contains("fFeeSectionMinimized"))121settings.setValue("fFeeSectionMinimized", true);122if (!settings.contains("nFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility123settings.setValue("nFeeRadio", 1); // custom124if (!settings.contains("nFeeRadio"))125settings.setValue("nFeeRadio", 0); // recommended126if (!settings.contains("nSmartFeeSliderPosition"))127settings.setValue("nSmartFeeSliderPosition", 0);128ui->groupFee->setId(ui->radioSmartFee, 0);129ui->groupFee->setId(ui->radioCustomFee, 1);130ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);131ui->customFee->SetAllowEmpty(false);132ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());133minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());135GUIUtil::ExceptionSafeConnect(ui->sendButton, &QPushButton::clicked, this, &SendCoinsDialog::sendButtonClicked);136}138void SendCoinsDialog::setClientModel(ClientModel *_clientModel)139{140this->clientModel = _clientModel;142if (_clientModel) {143connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateNumberOfBlocks);144}145}147void SendCoinsDialog::setModel(WalletModel *_model)148{149this->model = _model;151if(_model && _model->getOptionsModel())152{153for(int i = 0; i < ui->entries->count(); ++i)154{155SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());156if(entry)157{158entry->setModel(_model);159}160}162connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance);163connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::refreshBalance);164refreshBalance();166// Coin Control167connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::coinControlUpdateLabels);168connect(_model->getOptionsModel(), &OptionsModel::coinControlFeaturesChanged, this, &SendCoinsDialog::coinControlFeatureChanged);169ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures());170coinControlUpdateLabels();172// fee section173for (const int n : confTargets) {174ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));175}176connect(ui->confTargetSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel);177connect(ui->confTargetSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels);179connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::updateFeeSectionControls);180connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::coinControlUpdateLabels);182connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);183CAmount requiredFee = model->wallet().getRequiredFee(1000);184ui->customFee->SetMinValue(requiredFee);185if (ui->customFee->value() < requiredFee) {186ui->customFee->setValue(requiredFee);187}188ui->customFee->setSingleStep(requiredFee);189updateFeeSectionControls();190updateSmartFeeLabel();192if (model->wallet().hasExternalSigner()) {193//: "device" usually means a hardware wallet.194ui->sendButton->setText(tr("Sign on device"));195if (model->getOptionsModel()->hasSigner()) {196ui->sendButton->setEnabled(true);197ui->sendButton->setToolTip(tr("Connect your hardware wallet first."));198} else {199ui->sendButton->setEnabled(false);200//: "External signer" means using devices such as hardware wallets.201ui->sendButton->setToolTip(tr("Set external signer script path in Options -> Wallet"));202}203} else if (model->wallet().privateKeysDisabled()) {204ui->sendButton->setText(tr("Cr&eate Unsigned"));205ui->sendButton->setToolTip(tr("Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(CLIENT_NAME));206}208// set the smartfee-sliders default value (wallets default conf.target or last stored value)209QSettings settings;210if (settings.value("nSmartFeeSliderPosition").toInt() != 0) {211// migrate nSmartFeeSliderPosition to nConfTarget212// nConfTarget is available since 0.15 (replaced nSmartFeeSliderPosition)213int nConfirmTarget = 25 - settings.value("nSmartFeeSliderPosition").toInt(); // 25 == old slider range214settings.setValue("nConfTarget", nConfirmTarget);215settings.remove("nSmartFeeSliderPosition");216}217if (settings.value("nConfTarget").toInt() == 0)218ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->wallet().getConfirmTarget()));219else220ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));221}222}224SendCoinsDialog::~SendCoinsDialog()225{226QSettings settings;227settings.setValue("fFeeSectionMinimized", fFeeMinimized);228settings.setValue("nFeeRadio", ui->groupFee->checkedId());229settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex()));230settings.setValue("nTransactionFee", (qint64)ui->customFee->value());232delete ui;233}235bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informative_text, QString& detailed_text)236{237QList<SendCoinsRecipient> recipients;238bool valid = true;240for(int i = 0; i < ui->entries->count(); ++i)241{242SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());243if(entry)244{245if(entry->validate(model->node()))246{247recipients.append(entry->getValue());248}249else if (valid)250{
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.