5#if defined(HAVE_CONFIG_H)
31#include <validation.h>
33#include <QFontMetrics>
36#include <QTextDocument>
38static constexpr std::array
confTargets{2, 4, 6, 12, 24, 48, 144, 504, 1008};
40 if (index+1 >
static_cast<int>(
confTargets.size())) {
49 for (
unsigned int i = 0; i <
confTargets.size(); i++) {
63 fNewRecipientAllowed(true),
65 platformStyle(_platformStyle)
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);
116 if (!settings.contains(
"fFeeSectionMinimized"))
117 settings.setValue(
"fFeeSectionMinimized",
true);
118 if (!settings.contains(
"nFeeRadio") && settings.contains(
"nTransactionFee") && settings.value(
"nTransactionFee").toLongLong() > 0)
119 settings.setValue(
"nFeeRadio", 1);
120 if (!settings.contains(
"nFeeRadio"))
121 settings.setValue(
"nFeeRadio", 0);
122 if (!settings.contains(
"nSmartFeeSliderPosition"))
123 settings.setValue(
"nSmartFeeSliderPosition", 0);
124 if (!settings.contains(
"nTransactionFee"))
128 ui->
groupFee->button((
int)std::max(0, std::min(1, settings.value(
"nFeeRadio").toInt())))->setChecked(
true);
147 this->
model = _model;
151 for(
int i = 0; i <
ui->
entries->count(); ++i)
179#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
207 ui->
sendButton->setToolTip(tr(
"Connect your hardware wallet first."));
211 ui->
sendButton->setToolTip(tr(
"Set external signer script path in Options -> Wallet"));
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));
220 if (settings.value(
"nSmartFeeSliderPosition").toInt() != 0) {
223 int nConfirmTarget = 25 - settings.value(
"nSmartFeeSliderPosition").toInt();
224 settings.setValue(
"nConfTarget", nConfirmTarget);
225 settings.remove(
"nSmartFeeSliderPosition");
227 if (settings.value(
"nConfTarget").toInt() == 0)
238 settings.setValue(
"nFeeRadio",
ui->
groupFee->checkedId());
247 QList<SendCoinsRecipient> recipients;
250 for(
int i = 0; i <
ui->
entries->count(); ++i)
257 recipients.append(entry->
getValue());
267 if(!valid || recipients.isEmpty())
299 QStringList formatted;
309 QString address = rcp.address;
311 QString recipientElement;
314 if(rcp.label.length() > 0)
317 recipientElement.append(QString(
" (%1)").arg(address));
321 recipientElement.append(tr(
"%1 to %2").arg(amount, address));
324 formatted.append(recipientElement);
328 question_string.append(tr(
"Do you want to draft this transaction?"));
330 question_string.append(tr(
"Are you sure you want to send?"));
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));
337 question_string.append(tr(
"Please, review your transaction."));
339 question_string.append(
"</span>%1");
344 question_string.append(
"<hr /><b>");
345 question_string.append(tr(
"Transaction fee"));
346 question_string.append(
"</b>");
349 question_string.append(
" (" + QString::number((
double)
m_current_transaction->getTransactionSize() / 1000) +
" kB): ");
352 question_string.append(
"<span style='color:#aa0000; font-weight:bold;'>");
354 question_string.append(
"</span><br />");
357 question_string.append(
"<span style='font-size:10pt; font-weight:normal;'>");
359 question_string.append(tr(
"You can increase the fee later (signals Replace-By-Fee, BIP-125)."));
361 question_string.append(tr(
"Not signalling Replace-By-Fee, BIP-125."));
363 question_string.append(
"</span>");
367 question_string.append(
"<hr />");
369 QStringList alternativeUnits;
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") +
" ")));
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");
385 question_string = question_string.arg(
"<br /><br />" + formatted.at(0));
396 QString question_string, informative_text, detailed_text;
397 if (!
PrepareSendText(question_string, informative_text, detailed_text))
return;
403 confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
405 const auto retval =
static_cast<QMessageBox::StandardButton
>(confirmationDialog->exec());
407 if(retval != QMessageBox::Yes)
413 bool send_failure =
false;
417 bool complete =
false;
426 }
catch (
const std::runtime_error& e) {
427 QMessageBox::critical(
nullptr, tr(
"Sign failed"), e.what());
433 QMessageBox::critical(
nullptr, tr(
"External signer not found"),
"External signer not found");
439 QMessageBox::critical(
nullptr, tr(
"External signer failure"),
"External signer failure");
477 msgBox.setText(
"Unsigned Transaction");
478 msgBox.setInformativeText(
"The PSBT has been copied to the clipboard. You can also save it.");
479 msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
480 msgBox.setDefaultButton(QMessageBox::Discard);
481 switch (msgBox.exec()) {
482 case QMessageBox::Save: {
483 QString selectedFilter;
484 QString fileNameSuggestion =
"";
488 fileNameSuggestion.append(
" - ");
490 QString labelOrAddress = rcp.label.isEmpty() ? rcp.address : rcp.label;
492 fileNameSuggestion.append(labelOrAddress +
"-" + amount);
495 fileNameSuggestion.append(
".psbt");
497 tr(
"Save Transaction Data"), fileNameSuggestion,
499 tr(
"Partially Signed Transaction (Binary)") + QLatin1String(
" (*.psbt)"), &selectedFilter);
500 if (filename.isEmpty()) {
503 std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary);
509 case QMessageBox::Discard:
548 ui->
entries->takeAt(0)->widget()->deleteLater();
579 qApp->processEvents();
582 bar->setSliderPosition(bar->maximum());
602 entry->deleteLater();
609 for(
int i = 0; i <
ui->
entries->count(); ++i)
699 QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;
705 switch(sendCoinsReturn.
status)
708 msgParams.first = tr(
"The recipient address is not valid. Please recheck.");
711 msgParams.first = tr(
"The amount to pay must be larger than 0.");
714 msgParams.first = tr(
"The amount exceeds your balance.");
717 msgParams.first = tr(
"The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
720 msgParams.first = tr(
"Duplicate address found: addresses should only be used once each.");
723 msgParams.first = tr(
"Transaction creation failed!");
730 msgParams.first = tr(
"Payment request expired.");
739 Q_EMIT
message(tr(
"Send Coins"), msgParams.first, msgParams.second);
770 for (
int i = 0; i <
ui->
entries->count(); ++i) {
772 if (e && !e->isHidden() && e != entry) {
847 QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
854 ui->
labelFeeEstimation->setText(tr(
"Estimated to begin confirmation within %n block(s).",
"", returned_target));
908 if (!checked &&
model) {
926 if (state == Qt::Unchecked)
963 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?"),
964 QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
966 if(btnRetVal == QMessageBox::Yes)
981 if (!associatedLabel.isEmpty())
1004 for(
int i = 0; i <
ui->
entries->count(); ++i)
1007 if(entry && !entry->isHidden())
1035 : QMessageBox(parent), secDelay(_secDelay), confirmButtonText(_confirmButtonText)
1037 setIcon(QMessageBox::Question);
1038 setWindowTitle(title);
1040 setInformativeText(informative_text);
1041 setDetailedText(detailed_text);
1042 setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
1043 setDefaultButton(QMessageBox::Cancel);
1056 return QMessageBox::exec();
int64_t CAmount
Amount in satoshis (Can be negative)
const CChainParams & Params()
Return the currently selected parameters.
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
void setEnabled(bool fEnabled)
Enable/Disable.
void setSingleStep(const CAmount &step)
Set single step in satoshis.
void SetMinValue(const CAmount &value)
Set the minimum value in satoshis.
void setDisplayUnit(int unit)
Change unit used to display amount.
void setValue(const CAmount &value)
void SetAllowEmpty(bool allow)
If allow empty is set to false the field will be set to the minimum allowed value if left empty.
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as HTML string (with unit)
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
static QList< Unit > availableUnits()
Get list of units, for drop-down box.
@ MSG_INFORMATION
Predefined combinations for certain default usage cases.
Double ended buffer combining vector and stream-like interfaces.
Fee rate in satoshis per kilobyte: CAmount / kB.
CAmount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Model for Bitcoin network client.
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state)
static void updateLabels(CCoinControl &m_coin_control, WalletModel *, QDialog *)
static QList< CAmount > payAmounts
static bool fSubtractFeeFromAmount
int getDisplayUnit() const
bool getCoinControlFeatures() const
void coinControlFeaturesChanged(bool)
void displayUnitChanged(int unit)
void setEnabled(bool enabled)
Dialog for sending bitcoins.
void useAvailableBalance(SendCoinsEntry *entry)
ClientModel * clientModel
void coinControlChangeEdited(const QString &)
void coinControlChangeChecked(int)
void coinControlClipboardFee()
void updateNumberOfBlocks(int count, const QDateTime &blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state)
void on_buttonChooseFee_clicked()
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg=QString())
void setClientModel(ClientModel *clientModel)
void updateTabsAndLabels()
void updateFeeSectionControls()
std::unique_ptr< CCoinControl > m_coin_control
SendCoinsEntry * addEntry()
void pasteEntry(const SendCoinsRecipient &rv)
void updateFeeMinimizedLabel()
const PlatformStyle * platformStyle
void coinControlClipboardQuantity()
void coinControlButtonClicked()
void coinControlClipboardAfterFee()
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
bool PrepareSendText(QString &question_string, QString &informative_text, QString &detailed_text)
void sendButtonClicked(bool checked)
void setModel(WalletModel *model)
void coinControlClipboardLowOutput()
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
void setBalance(const interfaces::WalletBalances &balances)
void coinControlClipboardAmount()
void setAddress(const QString &address)
void coinControlClipboardChange()
std::unique_ptr< WalletModelTransaction > m_current_transaction
bool fNewRecipientAllowed
void removeEntry(SendCoinsEntry *entry)
void updateSmartFeeLabel()
void updateCoinControlState()
void coinControlClipboardBytes()
void message(const QString &title, const QString &message, unsigned int style)
SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent=nullptr)
void coinsSent(const uint256 &txid)
void on_buttonMinimizeFee_clicked()
void coinControlUpdateLabels()
void coinControlFeatureChanged(bool)
void minimizeFeeSection(bool fMinimize)
A single entry in the dialog for sending bitcoins.
void setAddress(const QString &address)
bool isClear()
Return whether the entry is still empty and unedited.
void subtractFeeFromAmountChanged()
void useAvailableBalance(SendCoinsEntry *entry)
void setValue(const SendCoinsRecipient &value)
void setModel(WalletModel *model)
void removeEntry(SendCoinsEntry *entry)
void setAmount(const CAmount &amount)
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
bool validate(interfaces::Node &node)
void checkSubtractFeeFromAmount()
SendCoinsRecipient getValue()
bool fSubtractFeeFromAmount
QAbstractButton * yesButton
QString confirmButtonText
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)
QWidget * scrollAreaWidgetContents
QLabel * labelCoinControlQuantity
QHBoxLayout * horizontalLayoutSmartFee
QLabel * fallbackFeeWarningLabel
QLabel * labelCoinControlAutomaticallySelected
QLabel * labelCoinControlBytes
QValidatedLineEdit * lineEditCoinControlChange
QLabel * labelCoinControlChange
QRadioButton * radioSmartFee
QLabel * labelCoinControlChangeLabel
QLabel * labelFeeMinimized
QPushButton * buttonMinimizeFee
QLabel * labelCustomFeeWarning
QLabel * labelCoinControlInsuffFunds
QCheckBox * checkBoxCoinControlChange
QLabel * labelBalanceName
QRadioButton * radioCustomFee
QPushButton * pushButtonCoinControl
void setupUi(QDialog *SendCoinsDialog)
QLabel * labelCustomPerKilobyte
QFrame * frameCoinControl
QComboBox * confTargetSelector
QFrame * frameFeeSelection
QPushButton * clearButton
QLabel * labelCoinControlLowOutput
QWidget * widgetCoinControl
BitcoinAmountField * customFee
QLabel * labelFeeEstimation
QLabel * labelCoinControlAfterFee
QLabel * labelCoinControlFee
QPushButton * buttonChooseFee
QLabel * labelCoinControlAmount
Interface to Bitcoin wallet from Qt view code.
interfaces::Node & node() const
SendCoinsReturn sendCoins(WalletModelTransaction &transaction)
AddressTableModel * getAddressTableModel()
OptionsModel * getOptionsModel()
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl &coinControl)
interfaces::Wallet & wallet() const
UnlockContext requestUnlock()
void balanceChanged(const interfaces::WalletBalances &balances)
QString getWalletName() const
@ AmountWithFeeExceedsBalance
@ TransactionCreationFailed
virtual TransactionError fillPSBT(int sighash_type, bool sign, bool bip32derivs, size_t *n_signed, PartiallySignedTransaction &psbtx, bool &complete)=0
Fill PSBT.
virtual CAmount getAvailableBalance(const CCoinControl &coin_control)=0
Get available balance.
virtual CAmount getRequiredFee(unsigned int tx_bytes)=0
Get required fee.
virtual unsigned int getConfirmTarget()=0
Get tx confirm target.
virtual bool hasExternalSigner()=0
virtual CAmount getDefaultMaxTxFee()=0
Get max tx fee.
virtual bool isSpendable(const CTxDestination &dest)=0
Return whether wallet has private key.
virtual WalletBalances getBalances()=0
Get balances.
virtual CAmount getMinimumFee(unsigned int tx_bytes, const CCoinControl &coin_control, int *returned_target, FeeReason *reason)=0
Get minimum fee.
virtual bool privateKeysDisabled()=0
@ EXTERNAL_SIGNER_NOT_FOUND
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg)
Utility functions used by the Bitcoin Qt UI.
QString HtmlEscape(const QString &str, bool fMultiLine)
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 ...
QString formatNiceTimeOffset(qint64 secs)
constexpr auto dialog_flags
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....
void ShowModalDialogAndDeleteOnClose(QDialog *dialog)
Shows a QDialog instance asynchronously, and deletes it on close.
int TextWidth(const QFontMetrics &fm, const QString &text)
Returns the distance in pixels appropriate for drawing a subsequent character after text.
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
void setClipboard(const QString &str)
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
bool FinalizeAndExtractPSBT(PartiallySignedTransaction &psbtx, CMutableTransaction &result)
Finalizes a PSBT if possible, and extracts it to a CMutableTransaction if it could be finalized.
int getConfTargetForIndex(int index)
int getIndexForConfTarget(int target)
static constexpr std::array confTargets
#define SEND_CONFIRM_DELAY
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
std::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
std::string EncodeBase64(Span< const unsigned char > input)
A mutable version of CTransaction.
A version of CTransaction with the PSBT format.
Collection of wallet balances.
CAmount watch_only_balance
static secp256k1_context * ctx
SynchronizationState
Current sync state passed to tip changed callbacks.
static const int PROTOCOL_VERSION
network protocol versioning
constexpr CAmount DEFAULT_PAY_TX_FEE
-paytxfee default