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] Spend cold-stake delegations #1391

Merged
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
2 changes: 2 additions & 0 deletions doc/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ Addresses in the dropdown of the "Send Transaction" and "Send Delegation" widget
**Custom Fee**: The custom fee selected when sending a transaction is now saved in the wallet database and persisted across multiple sends and wallet's restarts ([#1406](https://github.com/PIVX-Project/PIVX/pull/1406)).


**Include delegations in send**: The send and cold-staking page present a checkbox ([#1391](https://github.com/PIVX-Project/PIVX/pull/1391)) to make the automatic input selection algorithm include delegated (P2CS) utxos if needed. The option is unchecked by default.


### RPC/REST

Expand Down
4 changes: 2 additions & 2 deletions src/qt/pivx/coldstakingwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,9 @@ void ColdStakingWidget::onSendClicked()
QList<SendCoinsRecipient> recipients;
recipients.append(dest);

// Prepare transaction for getting txFee earlier
// Prepare transaction for getting txFee earlier (exlude delegated coins)
WalletModelTransaction currentTransaction(recipients);
WalletModel::SendCoinsReturn prepareStatus = walletModel->prepareTransaction(currentTransaction, CoinControlDialog::coinControl);
WalletModel::SendCoinsReturn prepareStatus = walletModel->prepareTransaction(currentTransaction, CoinControlDialog::coinControl, false);

// process prepareStatus and on error generate message shown to user
GuiTransactionsUtils::ProcessSendCoinsReturnAndInform(
Expand Down
21 changes: 17 additions & 4 deletions src/qt/pivx/forms/send.ui
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>send</class>
<widget class="QWidget" name="send">
Expand Down Expand Up @@ -366,17 +366,30 @@
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>20</number>
</property>
<property name="rightMargin">
<number>20</number>
</property>
<item>
<widget class="QCheckBox" name="checkBoxDelegations">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Include delegated</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<width>10</width>
<height>20</height>
</size>
</property>
Expand All @@ -402,7 +415,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<width>10</width>
<height>20</height>
</size>
</property>
Expand Down Expand Up @@ -431,7 +444,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<width>10</width>
<height>20</height>
</size>
</property>
Expand Down
3 changes: 2 additions & 1 deletion src/qt/pivx/masternodewizarddialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ bool MasterNodeWizardDialog::createMN()
WalletModelTransaction currentTransaction(recipients);
WalletModel::SendCoinsReturn prepareStatus;

prepareStatus = walletModel->prepareTransaction(currentTransaction);
// no coincontrol, no P2CS delegations
prepareStatus = walletModel->prepareTransaction(currentTransaction, nullptr, false);

QString returnMsg = "Unknown error";
// process prepareStatus and on error generate message shown to user
Expand Down
71 changes: 55 additions & 16 deletions src/qt/pivx/send.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ SendWidget::SendWidget(PIVXGUI* parent) :
connect(ui->btnChangeAddress, &OptionButton::clicked, this, &SendWidget::onChangeAddressClicked);
connect(ui->btnUri, &OptionButton::clicked, this, &SendWidget::onOpenUriClicked);
connect(ui->pushButtonReset, &QPushButton::clicked, [this](){ onResetCustomOptions(true); });
connect(ui->checkBoxDelegations, &QCheckBox::stateChanged, this, &SendWidget::onCheckBoxChanged);

setCssProperty(ui->coinWidget, "container-coin-type");
setCssProperty(ui->labelLine, "container-divider");
Expand Down Expand Up @@ -147,16 +148,9 @@ SendWidget::SendWidget(PIVXGUI* parent) :

void SendWidget::refreshView()
{
QString btnText;
if (ui->pushLeft->isChecked()) {
btnText = tr("Send PIV");
ui->pushButtonAddRecipient->setVisible(true);
} else {
btnText = tr("Send zPIV");
ui->pushButtonAddRecipient->setVisible(false);
}
ui->pushButtonSave->setText(btnText);

const bool isChecked = ui->pushLeft->isChecked();
ui->pushButtonSave->setText(isChecked ? tr("Send PIV") : tr("Send zPIV"));
ui->pushButtonAddRecipient->setVisible(isChecked);
refreshAmounts();
}

Expand All @@ -183,7 +177,9 @@ void SendWidget::refreshAmounts()
ui->labelTitleTotalRemaining->setText(tr("Total remaining from the selected UTXO"));
} else {
// Wallet's balance
totalAmount = (isZpiv ? walletModel->getZerocoinBalance() : walletModel->getBalance()) - total;
totalAmount = (isZpiv ?
walletModel->getZerocoinBalance() :
walletModel->getBalance(nullptr, fDelegationsChecked)) - total;
ui->labelTitleTotalRemaining->setText(tr("Total remaining"));
}
ui->labelAmountRemaining->setText(
Expand All @@ -193,6 +189,8 @@ void SendWidget::refreshAmounts()
isZpiv
)
);
// show or hide delegations checkbox if need be
showHideCheckBoxDelegations();
}

void SendWidget::loadClientModel()
Expand All @@ -206,10 +204,13 @@ void SendWidget::loadClientModel()

void SendWidget::loadWalletModel()
{
if (walletModel && walletModel->getOptionsModel()) {
// display unit
nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit();
if (walletModel) {
if (walletModel->getOptionsModel()) {
// display unit
nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit();
}

// set walletModel for entries
for (SendMultiRow *entry : entries) {
if (entry) {
entry->setWalletModel(walletModel);
Expand Down Expand Up @@ -253,6 +254,7 @@ void SendWidget::onResetCustomOptions(bool fRefreshAmounts)
CoinControlDialog::coinControl->SetNull();
ui->btnChangeAddress->setActive(false);
ui->btnCoinControl->setActive(false);
if (ui->checkBoxDelegations->isChecked()) ui->checkBoxDelegations->setChecked(false);
if (fRefreshAmounts) {
refreshAmounts();
}
Expand Down Expand Up @@ -324,13 +326,37 @@ void SendWidget::showEvent(QShowEvent *event)
{
// Set focus on last recipient address when Send-window is displayed
setFocusOnLastEntry();

// Update cached delegated balance
CAmount cachedDelegatedBalance_new = walletModel->getDelegatedBalance();
if (cachedDelegatedBalance != cachedDelegatedBalance_new) {
cachedDelegatedBalance = cachedDelegatedBalance_new;
refreshAmounts();
}
}

void SendWidget::setFocusOnLastEntry()
{
if (!entries.isEmpty()) entries.last()->setFocus();
}

void SendWidget::showHideCheckBoxDelegations()
{
// Show checkbox only when there is any available owned delegation,
// coincontrol is not selected, and we are trying to spend PIV (not zPIV)
const bool isZpiv = ui->pushRight->isChecked();
const bool isCControl = CoinControlDialog::coinControl->HasSelected();
const bool hasDel = cachedDelegatedBalance > 0;

const bool showCheckBox = !isZpiv && !isCControl && hasDel;
ui->checkBoxDelegations->setVisible(showCheckBox);
if (showCheckBox)
ui->checkBoxDelegations->setToolTip(
tr("Possibly spend coins delegated for cold-staking (currently available: %1").arg(
GUIUtil::formatBalance(cachedDelegatedBalance, nDisplayUnit, isZpiv))
);
}

void SendWidget::onSendClicked()
{
if (!walletModel || !walletModel->getOptionsModel())
Expand Down Expand Up @@ -375,7 +401,7 @@ bool SendWidget::send(QList<SendCoinsRecipient> recipients)
WalletModelTransaction currentTransaction(recipients);
WalletModel::SendCoinsReturn prepareStatus;

prepareStatus = walletModel->prepareTransaction(currentTransaction, CoinControlDialog::coinControl);
prepareStatus = walletModel->prepareTransaction(currentTransaction, CoinControlDialog::coinControl, fDelegationsChecked);

// process prepareStatus and on error generate message shown to user
GuiTransactionsUtils::ProcessSendCoinsReturnAndInform(
Expand All @@ -393,8 +419,9 @@ bool SendWidget::send(QList<SendCoinsRecipient> recipients)
}

showHideOp(true);
const bool fStakeDelegationVoided = currentTransaction.getTransaction()->fStakeDelegationVoided;
QString warningStr = QString();
if (currentTransaction.getTransaction()->fStakeDelegationVoided)
if (fStakeDelegationVoided)
warningStr = tr("WARNING:\nTransaction spends a cold-stake delegation, voiding it.\n"
"These coins will no longer be cold-staked.");
TxDetailDialog* dialog = new TxDetailDialog(window, true, warningStr);
Expand All @@ -414,6 +441,9 @@ bool SendWidget::send(QList<SendCoinsRecipient> recipients)
);

if (sendStatus.status == WalletModel::OK) {
// if delegations were spent, update cachedBalance
if (fStakeDelegationVoided)
cachedDelegatedBalance = walletModel->getDelegatedBalance();
clearAll(false);
inform(tr("Transaction sent"));
dialog->deleteLater();
Expand Down Expand Up @@ -654,6 +684,15 @@ void SendWidget::onValueChanged()
refreshAmounts();
}

void SendWidget::onCheckBoxChanged()
{
const bool checked = ui->checkBoxDelegations->isChecked();
if (checked != fDelegationsChecked) {
fDelegationsChecked = checked;
refreshAmounts();
}
}

void SendWidget::onPIVSelected(bool _isPIV)
{
isPIV = _isPIV;
Expand Down
5 changes: 5 additions & 0 deletions src/qt/pivx/send.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,21 @@ private Q_SLOTS:
void clearEntries();
void clearAll(bool fClearSettings = true);
void refreshView();
void onCheckBoxChanged();
void onContactMultiClicked();
void onDeleteClicked();
void onResetCustomOptions(bool fRefreshAmounts);
void onResetSettings();

private:
Ui::send *ui;
QPushButton *coinIcon;
QPushButton *btnContacts;

SendCustomFeeDialog* customFeeDialog = nullptr;
bool isCustomFeeSelected = false;
bool fDelegationsChecked = false;
CAmount cachedDelegatedBalance{0};

int nDisplayUnit;
QList<SendMultiRow*> entries;
Expand All @@ -96,6 +100,7 @@ private Q_SLOTS:
bool send(QList<SendCoinsRecipient> recipients);
bool sendZpiv(QList<SendCoinsRecipient> recipients);
void setFocusOnLastEntry();
void showHideCheckBoxDelegations();
void updateEntryLabels(QList<SendCoinsRecipient> recipients);
void setCustomFeeSelected(bool isSelected, const CAmount& customFee = DEFAULT_TRANSACTION_FEE);

Expand Down
13 changes: 7 additions & 6 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ bool WalletModel::isHDEnabled() const
{
return wallet->IsHDEnabled();
}

bool WalletModel::upgradeWallet(std::string& upgradeError)
{
// This action must be performed in a separate thread and not the main one.
Expand All @@ -98,20 +99,20 @@ bool WalletModel::upgradeWallet(std::string& upgradeError)
return wallet->Upgrade(upgradeError, prev_version);
}

CAmount WalletModel::getBalance(const CCoinControl* coinControl) const
CAmount WalletModel::getBalance(const CCoinControl* coinControl, bool fIncludeDelegated) const
{
if (coinControl) {
CAmount nBalance = 0;
std::vector<COutput> vCoins;
wallet->AvailableCoins(&vCoins, true, coinControl);
wallet->AvailableCoins(&vCoins, coinControl, fIncludeDelegated);
for (const COutput& out : vCoins)
if (out.fSpendable)
nBalance += out.tx->vout[out.i].nValue;

return nBalance;
}

return wallet->GetBalance();
return wallet->GetBalance(fIncludeDelegated);
}

CAmount WalletModel::getMinColdStakingAmount() const
Expand Down Expand Up @@ -404,7 +405,7 @@ bool WalletModel::updateAddressBookLabels(const CTxDestination& dest, const std:
return false;
}

WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction& transaction, const CCoinControl* coinControl)
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction& transaction, const CCoinControl* coinControl, bool fIncludeDelegations)
{
CAmount total = 0;
QList<SendCoinsRecipient> recipients = transaction.getRecipients();
Expand Down Expand Up @@ -481,7 +482,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return DuplicateAddress;
}

CAmount nBalance = getBalance(coinControl);
CAmount nBalance = getBalance(coinControl, fIncludeDelegations);

if (total > nBalance) {
return AmountExceedsBalance;
Expand Down Expand Up @@ -513,7 +514,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
recipients[0].inputType,
recipients[0].useSwiftTX,
0,
true);
fIncludeDelegations);
transaction.setTransactionFee(nFeeRequired);

if (recipients[0].useSwiftTX && newTx->GetValueOut() > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE) * COIN) {
Expand Down
4 changes: 2 additions & 2 deletions src/qt/walletmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class WalletModel : public QObject
bool isHDEnabled() const;
bool upgradeWallet(std::string& upgradeError);

CAmount getBalance(const CCoinControl* coinControl = NULL) const;
CAmount getBalance(const CCoinControl* coinControl = nullptr, bool fIncludeDelegated = true) const;
CAmount getUnconfirmedBalance() const;
CAmount getImmatureBalance() const;
CAmount getLockedBalance() const;
Expand Down Expand Up @@ -200,7 +200,7 @@ class WalletModel : public QObject
const CWalletTx* getTx(uint256 id);

// prepare transaction for getting txfee before sending coins
SendCoinsReturn prepareTransaction(WalletModelTransaction& transaction, const CCoinControl* coinControl = NULL);
SendCoinsReturn prepareTransaction(WalletModelTransaction& transaction, const CCoinControl* coinControl = NULL, bool fIncludeDelegations = true);

// Send coins to a list of recipients
SendCoinsReturn sendCoins(WalletModelTransaction& transaction);
Expand Down
10 changes: 9 additions & 1 deletion src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,15 @@ UniValue listunspent(const UniValue& params, bool fHelp)
std::vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(&vecOutputs, false, NULL, false, ALL_COINS, false, nWatchonlyConfig);
pwalletMain->AvailableCoins(&vecOutputs,
nullptr, // coin control
true, // include delegated
false, // include cold staking
ALL_COINS, // coin type
false, // only confirmed
false, // include zero value
false, // use IX
nWatchonlyConfig);
for (const COutput& out : vecOutputs) {
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue;
Expand Down
Loading