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