Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GUI] CoinControl Change #2859

Merged
merged 1 commit into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/coincontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
#ifndef BITCOIN_COINCONTROL_H
#define BITCOIN_COINCONTROL_H

#include "optional.h"
#include "policy/feerate.h"
#include "primitives/transaction.h"
#include "sapling/address.h"
#include "script/standard.h"
#include <unordered_set>

Expand All @@ -31,6 +33,8 @@ class OutPointWrapper {
class CCoinControl
{
public:
// TODO: upgrade those two fields to a single CWDestination?
Optional<libzcash::SaplingPaymentAddress> destShieldChange = boost::none;
CTxDestination destChange = CNoDestination();
//! If false, allows unselected inputs, but requires all selected inputs be used
bool fAllowOtherInputs;
Expand Down
36 changes: 27 additions & 9 deletions src/qt/pivx/send.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "addresstablemodel.h"
#include "clientmodel.h"
#include "coincontrol.h"
#include "destination_io.h"
#include "key_io.h"
#include "openuridialog.h"
#include "operationresult.h"
#include "optionsmodel.h"
Expand All @@ -18,6 +20,8 @@
#include "qt/pivx/sendchangeaddressdialog.h"
#include "qt/pivx/sendconfirmdialog.h"
#include "qt/walletmodel.h"
#include "sapling/address.h"
#include "sapling/key_io_sapling.h"
#include "script/standard.h"

#define REQUEST_PREPARE_TX 1
Expand Down Expand Up @@ -273,9 +277,11 @@ void SendWidget::resetCoinControl()

void SendWidget::resetChangeAddress()
{
if (coinControlDialog) coinControlDialog->coinControl->destChange = CNoDestination();
if (coinControlDialog) {
coinControlDialog->coinControl->destShieldChange = boost::none;
coinControlDialog->coinControl->destChange = CNoDestination();
}
ui->btnChangeAddress->setActive(false);
ui->btnChangeAddress->setVisible(isTransparent);
}

void SendWidget::clearEntries()
Expand Down Expand Up @@ -414,7 +420,7 @@ void SendWidget::ProcessSend(QList<SendCoinsRecipient>& recipients, bool hasShie
const std::function<bool(QList<SendCoinsRecipient>&)>& func)
{
// First check SPORK_20 (before unlock)
bool isShieldedTx = hasShieldedOutput || !isTransparent;
bool isShieldedTx = hasShieldedOutput || !isTransparent || coinControlDialog->coinControl->destShieldChange;
if (isShieldedTx) {
if (walletModel->isSaplingInMaintenance()) {
inform(tr("Sapling Protocol temporarily in maintenance. Shielded transactions disabled (SPORK 20)"));
Expand Down Expand Up @@ -468,7 +474,7 @@ void SendWidget::ProcessSend(QList<SendCoinsRecipient>& recipients, bool hasShie

OperationResult SendWidget::prepareShielded(WalletModelTransaction* currentTransaction, bool fromTransparent)
{
bool hasCoinsOrNotesSelected = coinControlDialog && coinControlDialog->coinControl && coinControlDialog->coinControl->HasSelected();
bool hasCoinsOrNotesSelected = coinControlDialog && coinControlDialog->coinControl;
return walletModel->PrepareShieldedTransaction(currentTransaction,
fromTransparent,
hasCoinsOrNotesSelected ? coinControlDialog->coinControl : nullptr);
Expand Down Expand Up @@ -605,15 +611,18 @@ void SendWidget::updateEntryLabels(const QList<SendCoinsRecipient>& recipients)
void SendWidget::onChangeAddressClicked()
{
showHideOp(true);
SendChangeAddressDialog* dialog = new SendChangeAddressDialog(window, walletModel);
SendChangeAddressDialog* dialog = new SendChangeAddressDialog(window, walletModel, isTransparent);
if (IsValidDestination(coinControlDialog->coinControl->destChange)) {
dialog->setAddress(QString::fromStdString(EncodeDestination(coinControlDialog->coinControl->destChange)));
} else if (coinControlDialog->coinControl->destShieldChange) {
dialog->setAddress(QString::fromStdString(KeyIO::EncodePaymentAddress(*(coinControlDialog->coinControl->destShieldChange))));
}

CTxDestination destChange = (openDialogWithOpaqueBackgroundY(dialog, window, 3, 5) ?
dialog->getDestination() : CNoDestination());
CWDestination destChange = (openDialogWithOpaqueBackgroundY(dialog, window, 3, 5) ?
dialog->getDestination() :
CNoDestination());

if (!IsValidDestination(destChange)) {
if (!Standard::IsValidDestination(destChange)) {
// no change address set
ui->btnChangeAddress->setActive(false);
} else {
Expand All @@ -627,7 +636,16 @@ void SendWidget::onChangeAddressClicked()
}

// save change address in coin control
coinControlDialog->coinControl->destChange = destChange;
const CTxDestination* transparentDest = Standard::GetTransparentDestination(destChange);
if (transparentDest) {
coinControlDialog->coinControl->destChange = *transparentDest;
coinControlDialog->coinControl->destShieldChange = boost::none;
}
const libzcash::SaplingPaymentAddress* shieldDest = Standard::GetShieldedDestination(destChange);
if (shieldDest) {
coinControlDialog->coinControl->destShieldChange = *shieldDest;
coinControlDialog->coinControl->destChange = CNoDestination();
}
dialog->deleteLater();
}

Expand Down
21 changes: 12 additions & 9 deletions src/qt/pivx/sendchangeaddressdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
#include "qt/pivx/forms/ui_sendchangeaddressdialog.h"
#include "qt/pivx/qtutils.h"

SendChangeAddressDialog::SendChangeAddressDialog(QWidget* parent, WalletModel* model) :
FocusedDialog(parent),
walletModel(model),
ui(new Ui::SendChangeAddressDialog)
SendChangeAddressDialog::SendChangeAddressDialog(QWidget* parent, WalletModel* model, bool isTransparent) : FocusedDialog(parent),
walletModel(model),
ui(new Ui::SendChangeAddressDialog)
{
// Change address
dest = CNoDestination();

this->isTransparent = isTransparent;
if (!walletModel) {
throw std::runtime_error(strprintf("%s: No wallet model set", __func__));
}
Expand Down Expand Up @@ -47,7 +46,7 @@ void SendChangeAddressDialog::setAddress(QString address)
ui->btnCancel->setText(tr("RESET"));
}

CTxDestination SendChangeAddressDialog::getDestination() const
CWDestination SendChangeAddressDialog::getDestination() const
{
return dest;
}
Expand All @@ -74,12 +73,16 @@ void SendChangeAddressDialog::accept()
QDialog::accept();
} else {
// validate address
bool isStakingAddr;
dest = DecodeDestination(ui->lineEditAddress->text().toStdString(), isStakingAddr);
if (!IsValidDestination(dest)) {
bool isStakingAddr = false;
bool isShield = false;
dest = Standard::DecodeDestination(ui->lineEditAddress->text().toStdString(), isStakingAddr, isShield);

if (!Standard::IsValidDestination(dest)) {
inform(tr("Invalid address"));
} else if (isStakingAddr) {
inform(tr("Cannot use cold staking addresses for change"));
} else if (!isShield && !isTransparent) {
inform(tr("Cannot use a transparent change for a shield transaction"));
} else {
QDialog::accept();
}
Expand Down
10 changes: 6 additions & 4 deletions src/qt/pivx/sendchangeaddressdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
#ifndef SENDCHANGEADDRESSDIALOG_H
#define SENDCHANGEADDRESSDIALOG_H

#include "script/standard.h"
#include "destination_io.h"
#include "qt/pivx/focuseddialog.h"
#include "qt/pivx/snackbar.h"
#include "script/standard.h"

class WalletModel;

Expand All @@ -20,19 +21,20 @@ class SendChangeAddressDialog : public FocusedDialog
Q_OBJECT

public:
explicit SendChangeAddressDialog(QWidget* parent, WalletModel* model);
explicit SendChangeAddressDialog(QWidget* parent, WalletModel* model, bool isTransparent);
~SendChangeAddressDialog();

void setAddress(QString address);
CTxDestination getDestination() const;
CWDestination getDestination() const;

void showEvent(QShowEvent* event) override;

private:
bool isTransparent;
WalletModel* walletModel;
Ui::SendChangeAddressDialog *ui;
SnackBar *snackBar = nullptr;
CTxDestination dest;
CWDestination dest;

void inform(const QString& text);

Expand Down
33 changes: 22 additions & 11 deletions src/sapling/sapling_operation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "net.h" // for g_connman
#include "policy/policy.h" // for GetDustThreshold
#include "sapling/key_io_sapling.h"
#include "script/standard.h"
#include "utilmoneystr.h" // for FormatMoney

struct TxValues
Expand Down Expand Up @@ -82,7 +83,7 @@ OperationResult SaplingOperation::build()
bool isFromtAddress = false;
bool isFromShielded = false;

if (coinControl) {
if (coinControl && coinControl->HasSelected()) {
// if coin control was selected it overrides any other defined configuration
std::vector<OutPointWrapper> coins;
coinControl->ListSelected(coins);
Expand Down Expand Up @@ -186,17 +187,27 @@ OperationResult SaplingOperation::build()
const auto& retCalc = checkTxValues(txValues, isFromtAddress, isFromShielded);
if (!retCalc) return retCalc;

// Set change address if we are using transparent funds
if (isFromtAddress) {
if (!tkeyChange) {
tkeyChange = new CReserveKey(wallet);
}
CPubKey vchPubKey;
if (!tkeyChange->GetReservedKey(vchPubKey, true)) {
return errorOut("Could not generate a taddr to use as a change address");
// By default look for a shield change address
if (coinControl && coinControl->destShieldChange) {
txBuilder.SendChangeTo(*coinControl->destShieldChange, ovk);

// If not found, and the transaction is transparent, set transparent change address
} else if (isFromtAddress) {
// Try to use coin control first
if (coinControl && IsValidDestination(coinControl->destChange)) {
txBuilder.SendChangeTo(coinControl->destChange);
// No Coin control! Then we can just use a random key from the keypool
} else {
if (!tkeyChange) {
tkeyChange = new CReserveKey(wallet);
}
CPubKey vchPubKey;
if (!tkeyChange->GetReservedKey(vchPubKey, true)) {
return errorOut("Could not generate a taddr to use as a change address");
}
CTxDestination changeAddr = vchPubKey.GetID();
txBuilder.SendChangeTo(changeAddr);
}
CTxDestination changeAddr = vchPubKey.GetID();
txBuilder.SendChangeTo(changeAddr);
}

// Build the transaction
Expand Down