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