Bitcoin Core  22.99.0
P2P Digital Currency
sendcoinsdialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2021 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #if defined(HAVE_CONFIG_H)
7 #endif
8 
9 #include <qt/sendcoinsdialog.h>
10 #include <qt/forms/ui_sendcoinsdialog.h>
11 
12 #include <qt/addresstablemodel.h>
13 #include <qt/bitcoinunits.h>
14 #include <qt/clientmodel.h>
15 #include <qt/coincontroldialog.h>
16 #include <qt/guiutil.h>
17 #include <qt/optionsmodel.h>
18 #include <qt/platformstyle.h>
19 #include <qt/sendcoinsentry.h>
20 
21 #include <chainparams.h>
22 #include <interfaces/node.h>
23 #include <key_io.h>
24 #include <node/ui_interface.h>
25 #include <policy/fees.h>
26 #include <txmempool.h>
27 #include <validation.h>
28 #include <wallet/coincontrol.h>
29 #include <wallet/fees.h>
30 #include <wallet/wallet.h>
31 
32 #include <chrono>
33 
34 #include <QFontMetrics>
35 #include <QScrollBar>
36 #include <QSettings>
37 #include <QTextDocument>
38 
41 
42 static constexpr std::array confTargets{2, 4, 6, 12, 24, 48, 144, 504, 1008};
43 int getConfTargetForIndex(int index) {
44  if (index+1 > static_cast<int>(confTargets.size())) {
45  return confTargets.back();
46  }
47  if (index < 0) {
48  return confTargets[0];
49  }
50  return confTargets[index];
51 }
52 int getIndexForConfTarget(int target) {
53  for (unsigned int i = 0; i < confTargets.size(); i++) {
54  if (confTargets[i] >= target) {
55  return i;
56  }
57  }
58  return confTargets.size() - 1;
59 }
60 
61 SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
62  QDialog(parent, GUIUtil::dialog_flags),
63  ui(new Ui::SendCoinsDialog),
64  clientModel(nullptr),
65  model(nullptr),
66  m_coin_control(new CCoinControl),
67  fNewRecipientAllowed(true),
68  fFeeMinimized(true),
69  platformStyle(_platformStyle)
70 {
71  ui->setupUi(this);
72 
73  if (!_platformStyle->getImagesOnButtons()) {
74  ui->addButton->setIcon(QIcon());
75  ui->clearButton->setIcon(QIcon());
76  ui->sendButton->setIcon(QIcon());
77  } else {
78  ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add"));
79  ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
80  ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send"));
81  }
82 
83  GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);
84 
85  addEntry();
86 
87  connect(ui->addButton, &QPushButton::clicked, this, &SendCoinsDialog::addEntry);
88  connect(ui->clearButton, &QPushButton::clicked, this, &SendCoinsDialog::clear);
89 
90  // Coin Control
91  connect(ui->pushButtonCoinControl, &QPushButton::clicked, this, &SendCoinsDialog::coinControlButtonClicked);
92  connect(ui->checkBoxCoinControlChange, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlChangeChecked);
93  connect(ui->lineEditCoinControlChange, &QValidatedLineEdit::textEdited, this, &SendCoinsDialog::coinControlChangeEdited);
94 
95  // Coin Control: clipboard actions
96  QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
97  QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
98  QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
99  QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
100  QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
101  QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
102  QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
103  connect(clipboardQuantityAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardQuantity);
104  connect(clipboardAmountAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAmount);
105  connect(clipboardFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardFee);
106  connect(clipboardAfterFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAfterFee);
107  connect(clipboardBytesAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardBytes);
108  connect(clipboardLowOutputAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardLowOutput);
109  connect(clipboardChangeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardChange);
110  ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
111  ui->labelCoinControlAmount->addAction(clipboardAmountAction);
112  ui->labelCoinControlFee->addAction(clipboardFeeAction);
113  ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
114  ui->labelCoinControlBytes->addAction(clipboardBytesAction);
115  ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
116  ui->labelCoinControlChange->addAction(clipboardChangeAction);
117 
118  // init transaction fee section
119  QSettings settings;
120  if (!settings.contains("fFeeSectionMinimized"))
121  settings.setValue("fFeeSectionMinimized", true);
122  if (!settings.contains("nFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility
123  settings.setValue("nFeeRadio", 1); // custom
124  if (!settings.contains("nFeeRadio"))
125  settings.setValue("nFeeRadio", 0); // recommended
126  if (!settings.contains("nSmartFeeSliderPosition"))
127  settings.setValue("nSmartFeeSliderPosition", 0);
128  if (!settings.contains("nTransactionFee"))
129  settings.setValue("nTransactionFee", (qint64)DEFAULT_PAY_TX_FEE);
130  ui->groupFee->setId(ui->radioSmartFee, 0);
131  ui->groupFee->setId(ui->radioCustomFee, 1);
132  ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);
133  ui->customFee->SetAllowEmpty(false);
134  ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
135  minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
136 
137  GUIUtil::ExceptionSafeConnect(ui->sendButton, &QPushButton::clicked, this, &SendCoinsDialog::sendButtonClicked);
138 }
139 
141 {
142  this->clientModel = _clientModel;
143 
144  if (_clientModel) {
146  }
147 }
148 
150 {
151  this->model = _model;
152 
153  if(_model && _model->getOptionsModel())
154  {
155  for(int i = 0; i < ui->entries->count(); ++i)
156  {
157  SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
158  if(entry)
159  {
160  entry->setModel(_model);
161  }
162  }
163 
164  interfaces::WalletBalances balances = _model->wallet().getBalances();
165  setBalance(balances);
169 
170  // Coin Control
173  ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures());
175 
176  // fee section
177  for (const int n : confTargets) {
178  ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));
179  }
180  connect(ui->confTargetSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel);
181  connect(ui->confTargetSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels);
182 
183 #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
184  connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::updateFeeSectionControls);
185  connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::coinControlUpdateLabels);
186 #else
187  connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls);
188  connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);
189 #endif
190 
192  connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateSmartFeeLabel);
193  connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
194  CAmount requiredFee = model->wallet().getRequiredFee(1000);
195  ui->customFee->SetMinValue(requiredFee);
196  if (ui->customFee->value() < requiredFee) {
197  ui->customFee->setValue(requiredFee);
198  }
199  ui->customFee->setSingleStep(requiredFee);
202 
203  // set default rbf checkbox state
204  ui->optInRBF->setCheckState(Qt::Checked);
205 
206  if (model->wallet().hasExternalSigner()) {
207  //: "device" usually means a hardware wallet.
208  ui->sendButton->setText(tr("Sign on device"));
209  if (gArgs.GetArg("-signer", "") != "") {
210  ui->sendButton->setEnabled(true);
211  ui->sendButton->setToolTip(tr("Connect your hardware wallet first."));
212  } else {
213  ui->sendButton->setEnabled(false);
214  //: "External signer" means using devices such as hardware wallets.
215  ui->sendButton->setToolTip(tr("Set external signer script path in Options -> Wallet"));
216  }
217  } else if (model->wallet().privateKeysDisabled()) {
218  ui->sendButton->setText(tr("Cr&eate Unsigned"));
219  ui->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(PACKAGE_NAME));
220  }
221 
222  // set the smartfee-sliders default value (wallets default conf.target or last stored value)
223  QSettings settings;
224  if (settings.value("nSmartFeeSliderPosition").toInt() != 0) {
225  // migrate nSmartFeeSliderPosition to nConfTarget
226  // nConfTarget is available since 0.15 (replaced nSmartFeeSliderPosition)
227  int nConfirmTarget = 25 - settings.value("nSmartFeeSliderPosition").toInt(); // 25 == old slider range
228  settings.setValue("nConfTarget", nConfirmTarget);
229  settings.remove("nSmartFeeSliderPosition");
230  }
231  if (settings.value("nConfTarget").toInt() == 0)
232  ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->wallet().getConfirmTarget()));
233  else
234  ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));
235  }
236 }
237 
239 {
240  QSettings settings;
241  settings.setValue("fFeeSectionMinimized", fFeeMinimized);
242  settings.setValue("nFeeRadio", ui->groupFee->checkedId());
243  settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex()));
244  settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
245 
246  delete ui;
247 }
248 
249 bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informative_text, QString& detailed_text)
250 {
251  QList<SendCoinsRecipient> recipients;
252  bool valid = true;
253 
254  for(int i = 0; i < ui->entries->count(); ++i)
255  {
256  SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
257  if(entry)
258  {
259  if(entry->validate(model->node()))
260  {
261  recipients.append(entry->getValue());
262  }
263  else if (valid)
264  {
265  ui->scrollArea->ensureWidgetVisible(entry);
266  valid = false;
267  }
268  }
269  }
270 
271  if(!valid || recipients.isEmpty())
272  {
273  return false;
274  }
275 
276  fNewRecipientAllowed = false;
278  if(!ctx.isValid())
279  {
280  // Unlock wallet was cancelled
281  fNewRecipientAllowed = true;
282  return false;
283  }
284 
285  // prepare transaction for getting txFee earlier
286  m_current_transaction = std::make_unique<WalletModelTransaction>(recipients);
287  WalletModel::SendCoinsReturn prepareStatus;
288 
290 
292 
293  // process prepareStatus and on error generate message shown to user
294  processSendCoinsReturn(prepareStatus,
296 
297  if(prepareStatus.status != WalletModel::OK) {
298  fNewRecipientAllowed = true;
299  return false;
300  }
301 
302  CAmount txFee = m_current_transaction->getTransactionFee();
303  QStringList formatted;
304  for (const SendCoinsRecipient &rcp : m_current_transaction->getRecipients())
305  {
306  // generate amount string with wallet name in case of multiwallet
307  QString amount = BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
308  if (model->isMultiwallet()) {
309  amount.append(tr(" from wallet '%1'").arg(GUIUtil::HtmlEscape(model->getWalletName())));
310  }
311 
312  // generate address string
313  QString address = rcp.address;
314 
315  QString recipientElement;
316 
317  {
318  if(rcp.label.length() > 0) // label with address
319  {
320  recipientElement.append(tr("%1 to '%2'").arg(amount, GUIUtil::HtmlEscape(rcp.label)));
321  recipientElement.append(QString(" (%1)").arg(address));
322  }
323  else // just address
324  {
325  recipientElement.append(tr("%1 to %2").arg(amount, address));
326  }
327  }
328  formatted.append(recipientElement);
329  }
330 
331  /*: Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify
332  that the displayed transaction details represent the transaction the user intends to create. */
333  question_string.append(tr("Do you want to create this transaction?"));
334  question_string.append("<br /><span style='font-size:10pt;'>");
336  /*: Text to inform a user attempting to create a transaction of their current options. At this stage,
337  a user can only create a PSBT. This string is displayed when private keys are disabled and an external
338  signer is not available. */
339  question_string.append(tr("Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME));
340  } else if (model->getOptionsModel()->getEnablePSBTControls()) {
341  /*: Text to inform a user attempting to create a transaction of their current options. At this stage,
342  a user can send their transaction or create a PSBT. This string is displayed when both private keys
343  and PSBT controls are enabled. */
344  question_string.append(tr("Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME));
345  } else {
346  /*: Text to prompt a user to review the details of the transaction they are attempting to send. */
347  question_string.append(tr("Please, review your transaction."));
348  }
349  question_string.append("</span>%1");
350 
351  if(txFee > 0)
352  {
353  // append fee string if a fee is required
354  question_string.append("<hr /><b>");
355  question_string.append(tr("Transaction fee"));
356  question_string.append("</b>");
357 
358  // append transaction size
359  question_string.append(" (" + QString::number((double)m_current_transaction->getTransactionSize() / 1000) + " kB): ");
360 
361  // append transaction fee value
362  question_string.append("<span style='color:#aa0000; font-weight:bold;'>");
363  question_string.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
364  question_string.append("</span><br />");
365 
366  // append RBF message according to transaction's signalling
367  question_string.append("<span style='font-size:10pt; font-weight:normal;'>");
368  if (ui->optInRBF->isChecked()) {
369  question_string.append(tr("You can increase the fee later (signals Replace-By-Fee, BIP-125)."));
370  } else {
371  question_string.append(tr("Not signalling Replace-By-Fee, BIP-125."));
372  }
373  question_string.append("</span>");
374  }
375 
376  // add total amount in all subdivision units
377  question_string.append("<hr />");
378  CAmount totalAmount = m_current_transaction->getTotalTransactionAmount() + txFee;
379  QStringList alternativeUnits;
381  {
382  if(u != model->getOptionsModel()->getDisplayUnit())
383  alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));
384  }
385  question_string.append(QString("<b>%1</b>: <b>%2</b>").arg(tr("Total Amount"))
387  question_string.append(QString("<br /><span style='font-size:10pt; font-weight:normal;'>(=%1)</span>")
388  .arg(alternativeUnits.join(" " + tr("or") + " ")));
389 
390  if (formatted.size() > 1) {
391  question_string = question_string.arg("");
392  informative_text = tr("To review recipient list click \"Show Details…\"");
393  detailed_text = formatted.join("\n\n");
394  } else {
395  question_string = question_string.arg("<br /><br />" + formatted.at(0));
396  }
397 
398  return true;
399 }
400 
401 void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
402 {
403  if(!model || !model->getOptionsModel())
404  return;
405 
406  QString question_string, informative_text, detailed_text;
407  if (!PrepareSendText(question_string, informative_text, detailed_text)) return;
409 
410  const QString confirmation = tr("Confirm send coins");
411  auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, !model->wallet().privateKeysDisabled(), model->getOptionsModel()->getEnablePSBTControls(), this);
412  confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
413  // TODO: Replace QDialog::exec() with safer QDialog::show().
414  const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec());
415 
416  if(retval != QMessageBox::Yes && retval != QMessageBox::Save)
417  {
418  fNewRecipientAllowed = true;
419  return;
420  }
421 
422  bool send_failure = false;
423  if (retval == QMessageBox::Save) {
425  PartiallySignedTransaction psbtx(mtx);
426  bool complete = false;
427  // Always fill without signing first. This prevents an external signer
428  // from being called prematurely and is not expensive.
429  TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete);
430  assert(!complete);
432  if (model->wallet().hasExternalSigner()) {
433  try {
434  err = model->wallet().fillPSBT(SIGHASH_ALL, true /* sign */, true /* bip32derivs */, nullptr, psbtx, complete);
435  } catch (const std::runtime_error& e) {
436  QMessageBox::critical(nullptr, tr("Sign failed"), e.what());
437  send_failure = true;
438  return;
439  }
441  //: "External signer" means using devices such as hardware wallets.
442  QMessageBox::critical(nullptr, tr("External signer not found"), "External signer not found");
443  send_failure = true;
444  return;
445  }
447  //: "External signer" means using devices such as hardware wallets.
448  QMessageBox::critical(nullptr, tr("External signer failure"), "External signer failure");
449  send_failure = true;
450  return;
451  }
452  if (err != TransactionError::OK) {
453  tfm::format(std::cerr, "Failed to sign PSBT");
455  send_failure = true;
456  return;
457  }
458  // fillPSBT does not always properly finalize
459  complete = FinalizeAndExtractPSBT(psbtx, mtx);
460  }
461 
462  // Broadcast transaction if complete (even with an external signer this
463  // is not always the case, e.g. in a multisig wallet).
464  if (complete) {
465  const CTransactionRef tx = MakeTransactionRef(mtx);
466  m_current_transaction->setWtx(tx);
468  // process sendStatus and on error generate message shown to user
469  processSendCoinsReturn(sendStatus);
470 
471  if (sendStatus.status == WalletModel::OK) {
472  Q_EMIT coinsSent(m_current_transaction->getWtx()->GetHash());
473  } else {
474  send_failure = true;
475  }
476  return;
477  }
478 
479  // Copy PSBT to clipboard and offer to save
480  assert(!complete);
481  // Serialize the PSBT
483  ssTx << psbtx;
484  GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str());
485  QMessageBox msgBox;
486  msgBox.setText("Unsigned Transaction");
487  msgBox.setInformativeText("The PSBT has been copied to the clipboard. You can also save it.");
488  msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
489  msgBox.setDefaultButton(QMessageBox::Discard);
490  switch (msgBox.exec()) {
491  case QMessageBox::Save: {
492  QString selectedFilter;
493  QString fileNameSuggestion = "";
494  bool first = true;
495  for (const SendCoinsRecipient &rcp : m_current_transaction->getRecipients()) {
496  if (!first) {
497  fileNameSuggestion.append(" - ");
498  }
499  QString labelOrAddress = rcp.label.isEmpty() ? rcp.address : rcp.label;
500  QString amount = BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
501  fileNameSuggestion.append(labelOrAddress + "-" + amount);
502  first = false;
503  }
504  fileNameSuggestion.append(".psbt");
505  QString filename = GUIUtil::getSaveFileName(this,
506  tr("Save Transaction Data"), fileNameSuggestion,
507  //: Expanded name of the binary PSBT file format. See: BIP 174.
508  tr("Partially Signed Transaction (Binary)") + QLatin1String(" (*.psbt)"), &selectedFilter);
509  if (filename.isEmpty()) {
510  return;
511  }
512  std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary);
513  out << ssTx.str();
514  out.close();
515  Q_EMIT message(tr("PSBT saved"), "PSBT saved to disk", CClientUIInterface::MSG_INFORMATION);
516  break;
517  }
518  case QMessageBox::Discard:
519  break;
520  default:
521  assert(false);
522  } // msgBox.exec()
523  } else {
525  // now send the prepared transaction
527  // process sendStatus and on error generate message shown to user
528  processSendCoinsReturn(sendStatus);
529 
530  if (sendStatus.status == WalletModel::OK) {
531  Q_EMIT coinsSent(m_current_transaction->getWtx()->GetHash());
532  } else {
533  send_failure = true;
534  }
535  }
536  if (!send_failure) {
537  accept();
538  m_coin_control->UnSelectAll();
540  }
541  fNewRecipientAllowed = true;
542  m_current_transaction.reset();
543 }
544 
546 {
547  m_current_transaction.reset();
548 
549  // Clear coin control settings
550  m_coin_control->UnSelectAll();
551  ui->checkBoxCoinControlChange->setChecked(false);
552  ui->lineEditCoinControlChange->clear();
554 
555  // Remove entries until only one left
556  while(ui->entries->count())
557  {
558  ui->entries->takeAt(0)->widget()->deleteLater();
559  }
560  addEntry();
561 
563 }
564 
566 {
567  clear();
568 }
569 
571 {
572  clear();
573 }
574 
576 {
577  SendCoinsEntry *entry = new SendCoinsEntry(platformStyle, this);
578  entry->setModel(model);
579  ui->entries->addWidget(entry);
584 
585  // Focus the field, so that entry can start immediately
586  entry->clear();
587  entry->setFocus();
588  ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
589  qApp->processEvents();
590  QScrollBar* bar = ui->scrollArea->verticalScrollBar();
591  if(bar)
592  bar->setSliderPosition(bar->maximum());
593 
595  return entry;
596 }
597 
599 {
600  setupTabChain(nullptr);
602 }
603 
605 {
606  entry->hide();
607 
608  // If the last entry is about to be removed add an empty one
609  if (ui->entries->count() == 1)
610  addEntry();
611 
612  entry->deleteLater();
613 
615 }
616 
617 QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
618 {
619  for(int i = 0; i < ui->entries->count(); ++i)
620  {
621  SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
622  if(entry)
623  {
624  prev = entry->setupTabChain(prev);
625  }
626  }
627  QWidget::setTabOrder(prev, ui->sendButton);
628  QWidget::setTabOrder(ui->sendButton, ui->clearButton);
629  QWidget::setTabOrder(ui->clearButton, ui->addButton);
630  return ui->addButton;
631 }
632 
633 void SendCoinsDialog::setAddress(const QString &address)
634 {
635  SendCoinsEntry *entry = nullptr;
636  // Replace the first entry if it is still unused
637  if(ui->entries->count() == 1)
638  {
639  SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
640  if(first->isClear())
641  {
642  entry = first;
643  }
644  }
645  if(!entry)
646  {
647  entry = addEntry();
648  }
649 
650  entry->setAddress(address);
651 }
652 
654 {
656  return;
657 
658  SendCoinsEntry *entry = nullptr;
659  // Replace the first entry if it is still unused
660  if(ui->entries->count() == 1)
661  {
662  SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
663  if(first->isClear())
664  {
665  entry = first;
666  }
667  }
668  if(!entry)
669  {
670  entry = addEntry();
671  }
672 
673  entry->setValue(rv);
675 }
676 
678 {
679  // Just paste the entry, all pre-checks
680  // are done in paymentserver.cpp.
681  pasteEntry(rv);
682  return true;
683 }
684 
686 {
687  if(model && model->getOptionsModel())
688  {
689  CAmount balance = balances.balance;
690  if (model->wallet().hasExternalSigner()) {
691  ui->labelBalanceName->setText(tr("External balance:"));
692  } else if (model->wallet().privateKeysDisabled()) {
693  balance = balances.watch_only_balance;
694  ui->labelBalanceName->setText(tr("Watch-only balance:"));
695  }
696  ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), balance));
697  }
698 }
699 
701 {
703  ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
705 }
706 
707 void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg)
708 {
709  QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;
710  // Default to a warning message, override if error message is needed
711  msgParams.second = CClientUIInterface::MSG_WARNING;
712 
713  // This comment is specific to SendCoinsDialog usage of WalletModel::SendCoinsReturn.
714  // All status values are used only in WalletModel::prepareTransaction()
715  switch(sendCoinsReturn.status)
716  {
718  msgParams.first = tr("The recipient address is not valid. Please recheck.");
719  break;
721  msgParams.first = tr("The amount to pay must be larger than 0.");
722  break;
724  msgParams.first = tr("The amount exceeds your balance.");
725  break;
727  msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
728  break;
730  msgParams.first = tr("Duplicate address found: addresses should only be used once each.");
731  break;
733  msgParams.first = tr("Transaction creation failed!");
734  msgParams.second = CClientUIInterface::MSG_ERROR;
735  break;
737  msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->wallet().getDefaultMaxTxFee()));
738  break;
740  msgParams.first = tr("Payment request expired.");
741  msgParams.second = CClientUIInterface::MSG_ERROR;
742  break;
743  // included to prevent a compiler warning.
744  case WalletModel::OK:
745  default:
746  return;
747  }
748 
749  Q_EMIT message(tr("Send Coins"), msgParams.first, msgParams.second);
750 }
751 
753 {
754  ui->labelFeeMinimized->setVisible(fMinimize);
755  ui->buttonChooseFee ->setVisible(fMinimize);
756  ui->buttonMinimizeFee->setVisible(!fMinimize);
757  ui->frameFeeSelection->setVisible(!fMinimize);
758  ui->horizontalLayoutSmartFee->setContentsMargins(0, (fMinimize ? 0 : 6), 0, 0);
759  fFeeMinimized = fMinimize;
760 }
761 
763 {
764  minimizeFeeSection(false);
765 }
766 
768 {
770  minimizeFeeSection(true);
771 }
772 
774 {
775  // Include watch-only for wallets without private key
777 
778  // Calculate available amount to send.
780  for (int i = 0; i < ui->entries->count(); ++i) {
781  SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
782  if (e && !e->isHidden() && e != entry) {
783  amount -= e->getValue().amount;
784  }
785  }
786 
787  if (amount > 0) {
789  entry->setAmount(amount);
790  } else {
791  entry->setAmount(0);
792  }
793 }
794 
796 {
797  ui->confTargetSelector ->setEnabled(ui->radioSmartFee->isChecked());
798  ui->labelSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
799  ui->labelSmartFee2 ->setEnabled(ui->radioSmartFee->isChecked());
800  ui->labelSmartFee3 ->setEnabled(ui->radioSmartFee->isChecked());
801  ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked());
802  ui->labelCustomFeeWarning ->setEnabled(ui->radioCustomFee->isChecked());
803  ui->labelCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked());
804  ui->customFee ->setEnabled(ui->radioCustomFee->isChecked());
805 }
806 
808 {
809  if(!model || !model->getOptionsModel())
810  return;
811 
812  if (ui->radioSmartFee->isChecked())
813  ui->labelFeeMinimized->setText(ui->labelSmartFee->text());
814  else {
815  ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kvB");
816  }
817 }
818 
820 {
821  if (ui->radioCustomFee->isChecked()) {
822  m_coin_control->m_feerate = CFeeRate(ui->customFee->value());
823  } else {
824  m_coin_control->m_feerate.reset();
825  }
826  // Avoid using global defaults when sending money from the GUI
827  // Either custom fee will be used or if not selected, the confirmation target from dropdown box
828  m_coin_control->m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
829  m_coin_control->m_signal_bip125_rbf = ui->optInRBF->isChecked();
830  // Include watch-only for wallets without private key
832 }
833 
834 void SendCoinsDialog::updateNumberOfBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state) {
835  if (sync_state == SynchronizationState::POST_INIT) {
837  }
838 }
839 
841 {
842  if(!model || !model->getOptionsModel())
843  return;
845  m_coin_control->m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
846  int returned_target;
847  FeeReason reason;
848  CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, *m_coin_control, &returned_target, &reason));
849 
850  ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kvB");
851 
852  if (reason == FeeReason::FALLBACK) {
853  ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
854  ui->labelFeeEstimation->setText("");
855  ui->fallbackFeeWarningLabel->setVisible(true);
856  int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
857  QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
858  ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }");
859  ui->fallbackFeeWarningLabel->setIndent(GUIUtil::TextWidth(QFontMetrics(ui->fallbackFeeWarningLabel->font()), "x"));
860  }
861  else
862  {
863  ui->labelSmartFee2->hide();
864  ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", returned_target));
865  ui->fallbackFeeWarningLabel->setVisible(false);
866  }
867 
869 }
870 
871 // Coin Control: copy label "Quantity" to clipboard
873 {
874  GUIUtil::setClipboard(ui->labelCoinControlQuantity->text());
875 }
876 
877 // Coin Control: copy label "Amount" to clipboard
879 {
880  GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));
881 }
882 
883 // Coin Control: copy label "Fee" to clipboard
885 {
886  GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
887 }
888 
889 // Coin Control: copy label "After fee" to clipboard
891 {
892  GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
893 }
894 
895 // Coin Control: copy label "Bytes" to clipboard
897 {
898  GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
899 }
900 
901 // Coin Control: copy label "Dust" to clipboard
903 {
904  GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text());
905 }
906 
907 // Coin Control: copy label "Change" to clipboard
909 {
910  GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
911 }
912 
913 // Coin Control: settings menu - coin control enabled/disabled by user
915 {
916  ui->frameCoinControl->setVisible(checked);
917 
918  if (!checked && model) { // coin control features disabled
919  m_coin_control = std::make_unique<CCoinControl>();
920  }
921 
923 }
924 
925 // Coin Control: button inputs -> show actual coin control dialog
927 {
929  connect(dlg, &QDialog::finished, this, &SendCoinsDialog::coinControlUpdateLabels);
931 }
932 
933 // Coin Control: checkbox custom change address
935 {
936  if (state == Qt::Unchecked)
937  {
938  m_coin_control->destChange = CNoDestination();
939  ui->labelCoinControlChangeLabel->clear();
940  }
941  else
942  // use this to re-validate an already entered address
943  coinControlChangeEdited(ui->lineEditCoinControlChange->text());
944 
945  ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked));
946 }
947 
948 // Coin Control: custom change address changed
950 {
951  if (model && model->getAddressTableModel())
952  {
953  // Default to no change address until verified
954  m_coin_control->destChange = CNoDestination();
955  ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
956 
957  const CTxDestination dest = DecodeDestination(text.toStdString());
958 
959  if (text.isEmpty()) // Nothing entered
960  {
961  ui->labelCoinControlChangeLabel->setText("");
962  }
963  else if (!IsValidDestination(dest)) // Invalid address
964  {
965  ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
966  }
967  else // Valid address
968  {
969  if (!model->wallet().isSpendable(dest)) {
970  ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
971 
972  // confirmation dialog
973  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?"),
974  QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
975 
976  if(btnRetVal == QMessageBox::Yes)
977  m_coin_control->destChange = dest;
978  else
979  {
980  ui->lineEditCoinControlChange->setText("");
981  ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");
982  ui->labelCoinControlChangeLabel->setText("");
983  }
984  }
985  else // Known change address
986  {
987  ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");
988 
989  // Query label
990  QString associatedLabel = model->getAddressTableModel()->labelForAddress(text);
991  if (!associatedLabel.isEmpty())
992  ui->labelCoinControlChangeLabel->setText(associatedLabel);
993  else
994  ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
995 
996  m_coin_control->destChange = dest;
997  }
998  }
999  }
1000 }
1001 
1002 // Coin Control: update labels
1004 {
1005  if (!model || !model->getOptionsModel())
1006  return;
1007 
1009 
1010  // set pay amounts
1013 
1014  for(int i = 0; i < ui->entries->count(); ++i)
1015  {
1016  SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
1017  if(entry && !entry->isHidden())
1018  {
1019  SendCoinsRecipient rcp = entry->getValue();
1021  if (rcp.fSubtractFeeFromAmount)
1023  }
1024  }
1025 
1026  if (m_coin_control->HasSelected())
1027  {
1028  // actual coin control calculation
1030 
1031  // show coin control stats
1032  ui->labelCoinControlAutomaticallySelected->hide();
1033  ui->widgetCoinControl->show();
1034  }
1035  else
1036  {
1037  // hide coin control stats
1038  ui->labelCoinControlAutomaticallySelected->show();
1039  ui->widgetCoinControl->hide();
1040  ui->labelCoinControlInsuffFunds->hide();
1041  }
1042 }
1043 
1044 SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, bool enable_send, bool always_show_unsigned, QWidget* parent)
1045  : QMessageBox(parent), secDelay(_secDelay), m_enable_send(enable_send)
1046 {
1047  setIcon(QMessageBox::Question);
1048  setWindowTitle(title); // On macOS, the window title is ignored (as required by the macOS Guidelines).
1049  setText(text);
1050  setInformativeText(informative_text);
1051  setDetailedText(detailed_text);
1052  setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
1053  if (always_show_unsigned || !enable_send) addButton(QMessageBox::Save);
1054  setDefaultButton(QMessageBox::Cancel);
1055  yesButton = button(QMessageBox::Yes);
1056  if (confirmButtonText.isEmpty()) {
1057  confirmButtonText = yesButton->text();
1058  }
1059  m_psbt_button = button(QMessageBox::Save);
1060  updateButtons();
1061  connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown);
1062 }
1063 
1065 {
1066  updateButtons();
1067  countDownTimer.start(1s);
1068  return QMessageBox::exec();
1069 }
1070 
1072 {
1073  secDelay--;
1074  updateButtons();
1075 
1076  if(secDelay <= 0)
1077  {
1078  countDownTimer.stop();
1079  }
1080 }
1081 
1083 {
1084  if(secDelay > 0)
1085  {
1086  yesButton->setEnabled(false);
1087  yesButton->setText(confirmButtonText + (m_enable_send ? (" (" + QString::number(secDelay) + ")") : QString("")));
1088  if (m_psbt_button) {
1089  m_psbt_button->setEnabled(false);
1090  m_psbt_button->setText(m_psbt_button_text + " (" + QString::number(secDelay) + ")");
1091  }
1092  }
1093  else
1094  {
1095  yesButton->setEnabled(m_enable_send);
1096  yesButton->setText(confirmButtonText);
1097  if (m_psbt_button) {
1098  m_psbt_button->setEnabled(true);
1100  }
1101  }
1102 }
SendCoinsRecipient::amount
CAmount amount
Definition: sendcoinsrecipient.h:33
ASYMP_UTF8
#define ASYMP_UTF8
Definition: coincontroldialog.h:30
ClientModel::numBlocksChanged
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state)
SendCoinsDialog::coinControlClipboardAmount
void coinControlClipboardAmount()
Definition: sendcoinsdialog.cpp:878
SendCoinsDialog::on_buttonChooseFee_clicked
void on_buttonChooseFee_clicked()
Definition: sendcoinsdialog.cpp:762
CClientUIInterface::MSG_INFORMATION
@ MSG_INFORMATION
Predefined combinations for certain default usage cases.
Definition: ui_interface.h:66
SendConfirmationDialog::m_psbt_button_text
QString m_psbt_button_text
Definition: sendcoinsdialog.h:133
WalletModel::getOptionsModel
OptionsModel * getOptionsModel()
Definition: walletmodel.cpp:287
SendCoinsEntry::setAddress
void setAddress(const QString &address)
Definition: sendcoinsentry.cpp:209
FeeReason
FeeReason
Definition: fees.h:43
SendCoinsDialog::fNewRecipientAllowed
bool fNewRecipientAllowed
Definition: sendcoinsdialog.h:69
count
static int count
Definition: tests.c:31
assert
assert(!tx.IsCoinBase())
CoinControlDialog::payAmounts
static QList< CAmount > payAmounts
Definition: coincontroldialog.h:53
tinyformat::format
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1062
SendConfirmationDialog
Definition: sendcoinsdialog.h:114
SendConfirmationDialog::m_psbt_button
QAbstractButton * m_psbt_button
Definition: sendcoinsdialog.h:128
SendCoinsDialog::coinsSent
void coinsSent(const uint256 &txid)
interfaces::Wallet::hasExternalSigner
virtual bool hasExternalSigner()=0
wallet.h
WalletModel
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:52
SendCoinsEntry::payAmountChanged
void payAmountChanged()
SEND_CONFIRM_DELAY
#define SEND_CONFIRM_DELAY
Definition: sendcoinsdialog.h:112
SendCoinsEntry::setValue
void setValue(const SendCoinsRecipient &value)
Definition: sendcoinsentry.cpp:192
interfaces::Wallet::getConfirmTarget
virtual unsigned int getConfirmTarget()=0
Get tx confirm target.
BitcoinUnits::formatWithUnit
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
Definition: bitcoinunits.cpp:150
BitcoinAmountField::valueChanged
void valueChanged()
key_io.h
PlatformStyle::SingleColorIcon
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
Definition: platformstyle.cpp:105
WalletModel::TransactionCreationFailed
@ TransactionCreationFailed
Definition: walletmodel.h:68
sendcoinsdialog.h
TransactionError::EXTERNAL_SIGNER_FAILED
@ EXTERNAL_SIGNER_FAILED
getIndexForConfTarget
int getIndexForConfTarget(int target)
Definition: sendcoinsdialog.cpp:52
WalletModel::getAddressTableModel
AddressTableModel * getAddressTableModel()
Definition: walletmodel.cpp:292
SendCoinsEntry::setFocus
void setFocus()
Definition: sendcoinsentry.cpp:225
AddressTableModel::labelForAddress
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
Definition: addresstablemodel.cpp:412
WalletModel::DuplicateAddress
@ DuplicateAddress
Definition: walletmodel.h:67
WalletModel::sendCoins
SendCoinsReturn sendCoins(WalletModelTransaction &transaction)
Definition: walletmodel.cpp:237
WalletModel::AmountWithFeeExceedsBalance
@ AmountWithFeeExceedsBalance
Definition: walletmodel.h:66
CoinControlDialog
Definition: coincontroldialog.h:42
SendCoinsDialog::updateNumberOfBlocks
void updateNumberOfBlocks(int count, const QDateTime &blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state)
Definition: sendcoinsdialog.cpp:834
WalletModel::AbsurdFee
@ AbsurdFee
Definition: walletmodel.h:69
GUIUtil
Utility functions used by the Bitcoin Qt UI.
Definition: bitcoingui.h:59
SendCoinsDialog::coinControlFeatureChanged
void coinControlFeatureChanged(bool)
Definition: sendcoinsdialog.cpp:914
SendCoinsEntry::setupTabChain
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
Definition: sendcoinsentry.cpp:180
WalletModel::isMultiwallet
bool isMultiwallet()
Definition: walletmodel.cpp:588
SendCoinsDialog::coinControlButtonClicked
void coinControlButtonClicked()
Definition: sendcoinsdialog.cpp:926
SendCoinsDialog::updateCoinControlState
void updateCoinControlState()
Definition: sendcoinsdialog.cpp:819
BitcoinUnits::formatHtmlWithUnit
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as HTML string (with unit)
Definition: bitcoinunits.cpp:155
MakeTransactionRef
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:387
OptionsModel::displayUnitChanged
void displayUnitChanged(int unit)
WalletModel::prepareTransaction
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const wallet::CCoinControl &coinControl)
Definition: walletmodel.cpp:153
GUIUtil::ExceptionSafeConnect
auto ExceptionSafeConnect(Sender sender, Signal signal, Receiver receiver, Slot method, Qt::ConnectionType type=Qt::AutoConnection)
A drop-in replacement of QObject::connect function (see: https://doc.qt.io/qt-5/qobject....
Definition: guiutil.h:392
SendCoinsDialog::addEntry
SendCoinsEntry * addEntry()
Definition: sendcoinsdialog.cpp:575
SendCoinsDialog::useAvailableBalance
void useAvailableBalance(SendCoinsEntry *entry)
Definition: sendcoinsdialog.cpp:773
EncodeBase64
std::string EncodeBase64(Span< const unsigned char > input)
Definition: strencodings.cpp:131
bitcoin-config.h
FinalizeAndExtractPSBT
bool FinalizeAndExtractPSBT(PartiallySignedTransaction &psbtx, CMutableTransaction &result)
Finalizes a PSBT if possible, and extracts it to a CMutableTransaction if it could be finalized.
Definition: psbt.cpp:348
chainparams.h
interfaces::Wallet::getMinimumFee
virtual CAmount getMinimumFee(unsigned int tx_bytes, const wallet::CCoinControl &coin_control, int *returned_target, FeeReason *reason)=0
Get minimum fee.
CTransactionRef
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:386
SendCoinsDialog::~SendCoinsDialog
~SendCoinsDialog()
Definition: sendcoinsdialog.cpp:238
WalletModel::requestUnlock
UnlockContext requestUnlock()
Definition: walletmodel.cpp:436
GUIUtil::dialog_flags
constexpr auto dialog_flags
Definition: guiutil.h:60
SendConfirmationDialog::m_enable_send
bool m_enable_send
Definition: sendcoinsdialog.h:132
interfaces::WalletBalances::balance
CAmount balance
Definition: wallet.h:367
CFeeRate
Fee rate in satoshis per kilobyte: CAmount / kB.
Definition: feerate.h:29
SendCoinsDialog::clientModel
ClientModel * clientModel
Definition: sendcoinsdialog.h:65
SendCoinsDialog::updateDisplayUnit
void updateDisplayUnit()
Definition: sendcoinsdialog.cpp:700
SendCoinsDialog::sendButtonClicked
void sendButtonClicked(bool checked)
Definition: sendcoinsdialog.cpp:401
GUIUtil::setClipboard
void setClipboard(const QString &str)
Definition: guiutil.cpp:646
txmempool.h
OptionsModel::getEnablePSBTControls
bool getEnablePSBTControls() const
Definition: optionsmodel.h:94
SendCoinsDialog::coinControlClipboardAfterFee
void coinControlClipboardAfterFee()
Definition: sendcoinsdialog.cpp:890
WalletModel::node
interfaces::Node & node() const
Definition: walletmodel.h:144
CoinControlDialog::fSubtractFeeFromAmount
static bool fSubtractFeeFromAmount
Definition: coincontroldialog.h:54
interfaces::WalletBalances::watch_only_balance
CAmount watch_only_balance
Definition: wallet.h:371
SendCoinsEntry::clear
void clear()
Definition: sendcoinsentry.cpp:94
fsbridge::ofstream
fs::ofstream ofstream
Definition: fs.h:235
SendCoinsRecipient
Definition: sendcoinsrecipient.h:19
fees.h
SendCoinsDialog::updateFeeMinimizedLabel
void updateFeeMinimizedLabel()
Definition: sendcoinsdialog.cpp:807
TransactionError
TransactionError
Definition: error.h:22
WalletModel::wallet
interfaces::Wallet & wallet() const
Definition: walletmodel.h:145
BitcoinUnits::availableUnits
static QList< Unit > availableUnits()
Get list of units, for drop-down box.
Definition: bitcoinunits.cpp:21
interfaces::WalletBalances
Collection of wallet balances.
Definition: wallet.h:365
WalletModel::AmountExceedsBalance
@ AmountExceedsBalance
Definition: walletmodel.h:65
CTxDestination
std::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:157
SendConfirmationDialog::confirmButtonText
QString confirmButtonText
Definition: sendcoinsdialog.h:131
FeeReason::FALLBACK
@ FALLBACK
IsValidDestination
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:332
GUIUtil::formatNiceTimeOffset
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:756
interfaces::Wallet::getRequiredFee
virtual CAmount getRequiredFee(unsigned int tx_bytes)=0
Get required fee.
sendcoinsentry.h
PACKAGE_NAME
#define PACKAGE_NAME
Definition: bitcoin-config.h:363
WalletModel::SendCoinsReturn::status
StatusCode status
Definition: walletmodel.h:98
PlatformStyle::getImagesOnButtons
bool getImagesOnButtons() const
Definition: platformstyle.h:21
node.h
SendCoinsDialog::handlePaymentRequest
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
Definition: sendcoinsdialog.cpp:677
TransactionError::EXTERNAL_SIGNER_NOT_FOUND
@ EXTERNAL_SIGNER_NOT_FOUND
OptionsModel::getCoinControlFeatures
bool getCoinControlFeatures() const
Definition: optionsmodel.h:92
CClientUIInterface::MSG_WARNING
@ MSG_WARNING
Definition: ui_interface.h:67
SendCoinsEntry::isClear
bool isClear()
Return whether the entry is still empty and unedited.
Definition: sendcoinsentry.cpp:220
ArgsManager::GetArg
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:590
CAmount
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
getConfTargetForIndex
int getConfTargetForIndex(int index)
Definition: sendcoinsdialog.cpp:43
SendCoinsDialog::m_current_transaction
std::unique_ptr< WalletModelTransaction > m_current_transaction
Definition: sendcoinsdialog.h:68
SendCoinsDialog
Dialog for sending bitcoins.
Definition: sendcoinsdialog.h:33
guiutil.h
WalletModel::getWalletName
QString getWalletName() const
Definition: walletmodel.cpp:577
SendConfirmationDialog::secDelay
int secDelay
Definition: sendcoinsdialog.h:130
SendCoinsDialog::minimizeFeeSection
void minimizeFeeSection(bool fMinimize)
Definition: sendcoinsdialog.cpp:752
SendCoinsDialog::setBalance
void setBalance(const interfaces::WalletBalances &balances)
Definition: sendcoinsdialog.cpp:685
SendCoinsDialog::setAddress
void setAddress(const QString &address)
Definition: sendcoinsdialog.cpp:633
SendCoinsDialog::setupTabChain
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
Definition: sendcoinsdialog.cpp:617
interfaces::Wallet::getBalances
virtual WalletBalances getBalances()=0
Get balances.
SendCoinsDialog::m_coin_control
std::unique_ptr< wallet::CCoinControl > m_coin_control
Definition: sendcoinsdialog.h:67
SendCoinsEntry::validate
bool validate(interfaces::Node &node)
Definition: sendcoinsentry.cpp:134
confTargets
static constexpr std::array confTargets
Definition: sendcoinsdialog.cpp:42
SendCoinsDialog::platformStyle
const PlatformStyle * platformStyle
Definition: sendcoinsdialog.h:71
CNoDestination
Definition: standard.h:73
gArgs
ArgsManager gArgs
Definition: system.cpp:85
SendCoinsDialog::PrepareSendText
bool PrepareSendText(QString &question_string, QString &informative_text, QString &detailed_text)
Definition: sendcoinsdialog.cpp:249
SendCoinsDialog::coinControlClipboardBytes
void coinControlClipboardBytes()
Definition: sendcoinsdialog.cpp:896
SendCoinsDialog::ui
Ui::SendCoinsDialog * ui
Definition: sendcoinsdialog.h:64
interfaces::Wallet::getDefaultMaxTxFee
virtual CAmount getDefaultMaxTxFee()=0
Get max tx fee.
SendCoinsDialog::updateTabsAndLabels
void updateTabsAndLabels()
Definition: sendcoinsdialog.cpp:598
SendCoinsEntry::setModel
void setModel(WalletModel *model)
Definition: sendcoinsentry.cpp:84
ui_interface.h
wallet::DEFAULT_PAY_TX_FEE
constexpr CAmount DEFAULT_PAY_TX_FEE
-paytxfee default
Definition: wallet.h:74
GUIUtil::getSaveFileName
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when ...
Definition: guiutil.cpp:287
platformstyle.h
SendCoinsDialog::coinControlClipboardChange
void coinControlClipboardChange()
Definition: sendcoinsdialog.cpp:908
SendConfirmationDialog::updateButtons
void updateButtons()
Definition: sendcoinsdialog.cpp:1082
CClientUIInterface::MSG_ERROR
@ MSG_ERROR
Definition: ui_interface.h:68
SendCoinsEntry::useAvailableBalance
void useAvailableBalance(SendCoinsEntry *entry)
ClientModel
Model for Bitcoin network client.
Definition: clientmodel.h:47
SIGHASH_ALL
@ SIGHASH_ALL
Definition: interpreter.h:27
Ui
Definition: addressbookpage.h:14
WalletModel::OK
@ OK
Definition: walletmodel.h:62
SendConfirmationDialog::SendConfirmationDialog
SendConfirmationDialog(const QString &title, const QString &text, const QString &informative_text="", const QString &detailed_text="", int secDelay=SEND_CONFIRM_DELAY, bool enable_send=true, bool always_show_unsigned=true, QWidget *parent=nullptr)
Definition: sendcoinsdialog.cpp:1044
SendConfirmationDialog::countDown
void countDown()
Definition: sendcoinsdialog.cpp:1071
GUIUtil::HtmlEscape
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:234
SendCoinsDialog::pasteEntry
void pasteEntry(const SendCoinsRecipient &rv)
Definition: sendcoinsdialog.cpp:653
SendConfirmationDialog::exec
int exec() override
Definition: sendcoinsdialog.cpp:1064
SendCoinsDialog::model
WalletModel * model
Definition: sendcoinsdialog.h:66
fees.h
WalletModel::UnlockContext
Definition: walletmodel.h:115
WalletModel::InvalidAmount
@ InvalidAmount
Definition: walletmodel.h:63
SendCoinsDialog::SendCoinsDialog
SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent=nullptr)
Definition: sendcoinsdialog.cpp:61
OptionsModel::getDisplayUnit
int getDisplayUnit() const
Definition: optionsmodel.h:89
SendCoinsDialog::setClientModel
void setClientModel(ClientModel *clientModel)
Definition: sendcoinsdialog.cpp:140
PartiallySignedTransaction
A version of CTransaction with the PSBT format.
Definition: psbt.h:668
WalletModel::InvalidAddress
@ InvalidAddress
Definition: walletmodel.h:64
TransactionError::OK
@ OK
No error.
SendCoinsEntry::removeEntry
void removeEntry(SendCoinsEntry *entry)
SendCoinsDialog::coinControlClipboardLowOutput
void coinControlClipboardLowOutput()
Definition: sendcoinsdialog.cpp:902
CoinControlDialog::updateLabels
static void updateLabels(wallet::CCoinControl &m_coin_control, WalletModel *, QDialog *)
Definition: coincontroldialog.cpp:386
BitcoinUnits::Unit
Unit
Bitcoin units.
Definition: bitcoinunits.h:41
DecodeDestination
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg, std::vector< int > *error_locations)
Definition: key_io.cpp:281
SendCoinsDialog::setModel
void setModel(WalletModel *model)
Definition: sendcoinsdialog.cpp:149
coincontroldialog.h
SendConfirmationDialog::yesButton
QAbstractButton * yesButton
Definition: sendcoinsdialog.h:127
SendCoinsDialog::coinControlChangeChecked
void coinControlChangeChecked(int)
Definition: sendcoinsdialog.cpp:934
Params
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:561
WalletModel::SendCoinsReturn
Definition: walletmodel.h:91
SendCoinsEntry::checkSubtractFeeFromAmount
void checkSubtractFeeFromAmount()
Definition: sendcoinsentry.cpp:119
bitcoinunits.h
SendCoinsDialog::message
void message(const QString &title, const QString &message, unsigned int style)
SendCoinsDialog::updateFeeSectionControls
void updateFeeSectionControls()
Definition: sendcoinsdialog.cpp:795
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:184
SendCoinsDialog::coinControlClipboardFee
void coinControlClipboardFee()
Definition: sendcoinsdialog.cpp:884
GUIUtil::ShowModalDialogAndDeleteOnClose
void ShowModalDialogAndDeleteOnClose(QDialog *dialog)
Shows a QDialog instance asynchronously, and deletes it on close.
Definition: guiutil.cpp:982
SendCoinsDialog::coinControlChangeEdited
void coinControlChangeEdited(const QString &)
Definition: sendcoinsdialog.cpp:949
SendCoinsEntry
A single entry in the dialog for sending bitcoins.
Definition: sendcoinsentry.h:28
SendCoinsDialog::coinControlUpdateLabels
void coinControlUpdateLabels()
Definition: sendcoinsdialog.cpp:1003
SendCoinsDialog::removeEntry
void removeEntry(SendCoinsEntry *entry)
Definition: sendcoinsdialog.cpp:604
SER_NETWORK
@ SER_NETWORK
Definition: serialize.h:138
GUIUtil::TextWidth
int TextWidth(const QFontMetrics &fm, const QString &text)
Returns the distance in pixels appropriate for drawing a subsequent character after text.
Definition: guiutil.cpp:884
SendCoinsDialog::fFeeMinimized
bool fFeeMinimized
Definition: sendcoinsdialog.h:70
SynchronizationState
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:105
SendCoinsEntry::subtractFeeFromAmountChanged
void subtractFeeFromAmountChanged()
SendCoinsDialog::clear
void clear()
Definition: sendcoinsdialog.cpp:545
optionsmodel.h
WalletModel::PaymentRequestExpired
@ PaymentRequestExpired
Definition: walletmodel.h:70
interfaces::Wallet::isSpendable
virtual bool isSpendable(const CTxDestination &dest)=0
Return whether wallet has private key.
SendCoinsDialog::accept
void accept() override
Definition: sendcoinsdialog.cpp:570
CMutableTransaction
A mutable version of CTransaction.
Definition: transaction.h:344
coincontrol.h
CFeeRate::GetFeePerK
CAmount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Definition: feerate.h:57
WalletModel::balanceChanged
void balanceChanged(const interfaces::WalletBalances &balances)
PlatformStyle
Definition: platformstyle.h:13
CDataStream::str
std::string str() const
Definition: streams.h:222
GUIUtil::setupAddressWidget
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
Definition: guiutil.cpp:115
SendCoinsEntry::setAmount
void setAmount(const CAmount &amount)
Definition: sendcoinsentry.cpp:215
interfaces::Wallet::fillPSBT
virtual TransactionError fillPSBT(int sighash_type, bool sign, bool bip32derivs, size_t *n_signed, PartiallySignedTransaction &psbtx, bool &complete)=0
Fill PSBT.
interfaces::Wallet::privateKeysDisabled
virtual bool privateKeysDisabled()=0
wallet::CCoinControl
Coin Control Features.
Definition: coincontrol.h:29
addresstablemodel.h
SendCoinsDialog::processSendCoinsReturn
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg=QString())
Definition: sendcoinsdialog.cpp:707
SendCoinsDialog::updateSmartFeeLabel
void updateSmartFeeLabel()
Definition: sendcoinsdialog.cpp:840
SynchronizationState::POST_INIT
@ POST_INIT
SendCoinsDialog::coinControlClipboardQuantity
void coinControlClipboardQuantity()
Definition: sendcoinsdialog.cpp:872
clientmodel.h
ctx
static secp256k1_context * ctx
Definition: tests.c:32
OptionsModel::coinControlFeaturesChanged
void coinControlFeaturesChanged(bool)
SendCoinsRecipient::fSubtractFeeFromAmount
bool fSubtractFeeFromAmount
Definition: sendcoinsrecipient.h:42
SendCoinsEntry::getValue
SendCoinsRecipient getValue()
Definition: sendcoinsentry.cpp:169
SendCoinsDialog::on_buttonMinimizeFee_clicked
void on_buttonMinimizeFee_clicked()
Definition: sendcoinsdialog.cpp:767
interfaces::Wallet::getAvailableBalance
virtual CAmount getAvailableBalance(const wallet::CCoinControl &coin_control)=0
Get available balance.
PROTOCOL_VERSION
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
SendConfirmationDialog::countDownTimer
QTimer countDownTimer
Definition: sendcoinsdialog.h:129
SendCoinsDialog::reject
void reject() override
Definition: sendcoinsdialog.cpp:565