diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index f7cf72dcec..74522ea695 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -799,7 +799,9 @@ QString formatAssetAmount(const CAsset& asset, const CAmount& amount, const int QString formatMultiAssetAmount(const CAmountMap& amountmap, const int bitcoin_unit, BitcoinUnits::SeparatorStyle separators, QString line_separator) { QStringList ret; - ret << formatAssetAmount(Params().GetConsensus().pegged_asset, amountmap.count(Params().GetConsensus().pegged_asset) ? amountmap.at(Params().GetConsensus().pegged_asset) : 0, bitcoin_unit, separators); + if (bitcoin_unit >= 0) { + ret << formatAssetAmount(Params().GetConsensus().pegged_asset, amountmap.count(Params().GetConsensus().pegged_asset) ? amountmap.at(Params().GetConsensus().pegged_asset) : 0, bitcoin_unit, separators); + } for (const auto& assetamount : amountmap) { if (assetamount.first == Params().GetConsensus().pegged_asset) { // Already handled first diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index cbecd4cbfb..a57d732184 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -275,11 +275,12 @@ void SendCoinsDialog::on_sendButton_clicked() CAmount txFee = currentTransaction.getTransactionFee(); // Format confirmation message + int bitcoin_unit = model->getOptionsModel()->getDisplayUnit(); QStringList formatted; for (const SendAssetsRecipient &rcp : currentTransaction.getRecipients()) { // generate bold amount string with wallet name in case of multiwallet - QString amount = "" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); + QString amount = "" + GUIUtil::formatAssetAmount(rcp.asset, rcp.asset_amount, bitcoin_unit, BitcoinUnits::separatorStandard, true); if (model->isMultiwallet()) { amount.append(" "+tr("from wallet %1").arg(GUIUtil::HtmlEscape(model->getWalletName()))+" "); } @@ -347,17 +348,22 @@ void SendCoinsDialog::on_sendButton_clicked() // add total amount in all subdivision units questionString.append("
"); - CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; + CAmountMap totalAmount = currentTransaction.getTotalTransactionAmount(); + totalAmount[Params().GetConsensus().pegged_asset] += txFee; QStringList alternativeUnits; for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) - alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); + alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount[Params().GetConsensus().pegged_asset])); } questionString.append(QString("%1: %2").arg(tr("Total Amount")) - .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); + .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount[Params().GetConsensus().pegged_asset]))); questionString.append(QString("
(=%1)") .arg(alternativeUnits.join(" " + tr("or") + " "))); + totalAmount.erase(Params().GetConsensus().pegged_asset); + if (!!totalAmount) { + questionString.append(" " + tr("and") + "
" + GUIUtil::formatMultiAssetAmount(totalAmount, -1 /*bitcoin unit, hide*/, BitcoinUnits::separatorStandard, ";
")); + } SendConfirmationDialog confirmationDialog(tr("Confirm send coins"), questionString.arg(formatted.join("
")), SEND_CONFIRM_DELAY, this); @@ -623,7 +629,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry) for (int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry* e = qobject_cast(ui->entries->itemAt(i)->widget()); if (e && !e->isHidden() && e != entry) { - amount -= e->getValue().amount; + amount -= e->getValue().asset_amount; } } @@ -871,8 +877,10 @@ void SendCoinsDialog::coinControlUpdateLabels() SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); if(entry && !entry->isHidden()) { - auto rcp = entry->getValue(); - CoinControlDialog::payAmounts.append(rcp.amount); + SendAssetsRecipient rcp = entry->getValue(); + if (rcp.asset == Params().GetConsensus().pegged_asset) { + CoinControlDialog::payAmounts.append(rcp.asset_amount); + } if (rcp.fSubtractFeeFromAmount) CoinControlDialog::fSubtractFeeFromAmount = true; } diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index ed3436b68e..d3ee221107 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -14,6 +14,8 @@ #include #include +#include + SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) : QStackedWidget(parent), ui(new Ui::SendCoinsEntry), @@ -152,14 +154,15 @@ bool SendCoinsEntry::validate(interfaces::Node& node) } // Sending a zero amount is invalid - if (ui->payAmount->value(0) <= 0) + const auto send_assets = ui->payAmount->fullValue(); + if (send_assets.second <= 0) { ui->payAmount->setValid(false); retval = false; } // Reject dust outputs: - if (retval && GUIUtil::isDust(node, ui->payTo->text(), ui->payAmount->value())) { + if (retval && send_assets.first == ::policyAsset && GUIUtil::isDust(node, ui->payTo->text(), ui->payAmount->value())) { ui->payAmount->setValid(false); retval = false; } @@ -176,7 +179,7 @@ SendAssetsRecipient SendCoinsEntry::getValue() // Normal payment recipient.address = ui->payTo->text(); recipient.label = ui->addAsLabel->text(); - recipient.amount = ui->payAmount->value(); + std::tie(recipient.asset, recipient.asset_amount) = ui->payAmount->fullValue(); recipient.message = ui->messageTextLabel->text(); recipient.fSubtractFeeFromAmount = (ui->checkboxSubtractFeeFromAmount->checkState() == Qt::Checked); @@ -205,7 +208,7 @@ void SendCoinsEntry::setValue(const SendAssetsRecipient &value) { ui->payTo_is->setText(recipient.address); ui->memoTextLabel_is->setText(recipient.message); - ui->payAmount_is->setValue(recipient.amount); + ui->payAmount_is->setFullValue(recipient.asset, recipient.asset_amount); ui->payAmount_is->setReadOnly(true); setCurrentWidget(ui->SendCoins_UnauthenticatedPaymentRequest); } @@ -213,7 +216,7 @@ void SendCoinsEntry::setValue(const SendAssetsRecipient &value) { ui->payTo_s->setText(recipient.authenticatedMerchant); ui->memoTextLabel_s->setText(recipient.message); - ui->payAmount_s->setValue(recipient.amount); + ui->payAmount_s->setFullValue(recipient.asset, recipient.asset_amount); ui->payAmount_s->setReadOnly(true); setCurrentWidget(ui->SendCoins_AuthenticatedPaymentRequest); } @@ -229,7 +232,7 @@ void SendCoinsEntry::setValue(const SendAssetsRecipient &value) ui->payTo->setText(recipient.address); // this may set a label from addressbook if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, don't overwrite with an empty label ui->addAsLabel->setText(recipient.label); - ui->payAmount->setValue(recipient.amount); + ui->payAmount->setFullValue(recipient.asset, recipient.asset_amount); } } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 98a7555c97..7131cd7ef0 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -20,6 +20,7 @@ #include // for GetBoolArg #include #include +#include #include @@ -31,7 +32,8 @@ SendAssetsRecipient::SendAssetsRecipient(SendCoinsRecipient r) : address(r.address), label(r.label), - amount(r.amount), + asset(Params().GetConsensus().pegged_asset), + asset_amount(r.amount), message(r.message), paymentRequest(r.paymentRequest), authenticatedMerchant(r.authenticatedMerchant), @@ -39,6 +41,8 @@ SendAssetsRecipient::SendAssetsRecipient(SendCoinsRecipient r) : { } +#define SendCoinsRecipient SendAssetsRecipient + WalletModel::WalletModel(std::unique_ptr wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *_optionsModel, QObject *parent) : QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(0), transactionTableModel(0), @@ -149,9 +153,9 @@ bool WalletModel::validateAddress(const QString &address) WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl) { - CAmount total = 0; + CAmountMap total; bool fSubtractFeeFromAmount = false; - auto recipients = transaction.getRecipients(); + QList recipients = transaction.getRecipients(); std::vector vecSend; if(recipients.empty()) @@ -163,7 +167,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact int nAddresses = 0; // Pre-check input data for validity - for (const SendAssetsRecipient &rcp : recipients) + for (const SendCoinsRecipient &rcp : recipients) { if (rcp.fSubtractFeeFromAmount) fSubtractFeeFromAmount = true; @@ -187,7 +191,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact { return InvalidAmount; } - total += subtotal; + total[Params().GetConsensus().pegged_asset] += subtotal; } else { // User-entered bitcoin address / amount: @@ -195,18 +199,20 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact { return InvalidAddress; } - if(rcp.amount <= 0) + if(rcp.asset_amount <= 0) { return InvalidAmount; } setAddress.insert(rcp.address); ++nAddresses; - CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString())); - CRecipient recipient = {scriptPubKey, rcp.amount, ::policyAsset, CPubKey(), rcp.fSubtractFeeFromAmount}; + CTxDestination dest = DecodeDestination(rcp.address.toStdString()); + CScript scriptPubKey = GetScriptForDestination(dest); + CPubKey confidentiality_pubkey = GetDestinationBlindingKey(dest); + CRecipient recipient = {scriptPubKey, rcp.asset_amount, rcp.asset, confidentiality_pubkey, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); - total += rcp.amount; + total[rcp.asset] += rcp.asset_amount; } } if(setAddress.size() != nAddresses) @@ -214,7 +220,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return DuplicateAddress; } - CAmount nBalance = m_wallet->getAvailableBalance(coinControl)[::policyAsset]; + CAmountMap nBalance = m_wallet->getAvailableBalance(coinControl); if(total > nBalance) { @@ -227,14 +233,16 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact std::string strFailReason; auto& newTx = transaction.getWtx(); + std::vector out_amounts; newTx = m_wallet->createTransaction(vecSend, coinControl, true /* sign */, nChangePosRet, nFeeRequired, strFailReason); transaction.setTransactionFee(nFeeRequired); if (fSubtractFeeFromAmount && newTx) - transaction.reassignAmounts(nChangePosRet); + transaction.reassignAmounts(out_amounts, nChangePosRet); if(!newTx) { - if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance) + total[Params().GetConsensus().pegged_asset] += nFeeRequired; + if(!fSubtractFeeFromAmount && total > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance); } @@ -259,7 +267,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran { std::vector> vOrderForm; - for (const SendAssetsRecipient &rcp : transaction.getRecipients()) + for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { if (rcp.paymentRequest.IsInitialized()) { @@ -289,7 +297,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran // Add addresses / update labels that we've sent to the address book, // and emit coinsSent signal for each recipient - for (const SendAssetsRecipient &rcp : transaction.getRecipients()) + for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { // Don't touch the address book when we have a payment request if (!rcp.paymentRequest.IsInitialized()) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index fdc2d04ea2..a16b374b3e 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -113,7 +113,8 @@ public: public: QString address; QString label; - CAmount amount; + CAsset asset; + CAmount asset_amount; QString message; PaymentRequestPlus paymentRequest; diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 50b9980af4..ab473a3fc3 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -7,13 +7,15 @@ #include #include -WalletModelTransaction::WalletModelTransaction(const QList &_recipients) : +#define SendCoinsRecipient SendAssetsRecipient + +WalletModelTransaction::WalletModelTransaction(const QList &_recipients) : recipients(_recipients), fee(0) { } -QList WalletModelTransaction::getRecipients() const +QList WalletModelTransaction::getRecipients() const { return recipients; } @@ -38,9 +40,8 @@ void WalletModelTransaction::setTransactionFee(const CAmount& newFee) fee = newFee; } -void WalletModelTransaction::reassignAmounts(int nChangePosRet) +void WalletModelTransaction::reassignAmounts(const std::vector& outAmounts, int nChangePosRet) { - const CTransaction* walletTransaction = &wtx->get(); int i = 0; for (auto it = recipients.begin(); it != recipients.end(); ++it) { @@ -56,27 +57,27 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet) if (out.amount() <= 0) continue; if (i == nChangePosRet) i++; - subtotal += walletTransaction->vout[i].nValue.GetAmount(); + subtotal += outAmounts[i]; i++; } - rcp.amount = subtotal; + rcp.asset_amount = subtotal; } else // normal recipient (no payment request) { if (i == nChangePosRet) i++; - rcp.amount = walletTransaction->vout[i].nValue.GetAmount(); + rcp.asset_amount = outAmounts[i]; i++; } } } -CAmount WalletModelTransaction::getTotalTransactionAmount() const +CAmountMap WalletModelTransaction::getTotalTransactionAmount() const { - CAmount totalTransactionAmount = 0; - for (const SendAssetsRecipient &rcp : recipients) + CAmountMap totalTransactionAmount; + for (const auto &rcp : recipients) { - totalTransactionAmount += rcp.amount; + totalTransactionAmount[rcp.asset] += rcp.asset_amount; } return totalTransactionAmount; } diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index 87d1915ab8..0a83f70c4b 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -32,9 +32,9 @@ public: void setTransactionFee(const CAmount& newFee); CAmount getTransactionFee() const; - CAmount getTotalTransactionAmount() const; + CAmountMap getTotalTransactionAmount() const; - void reassignAmounts(int nChangePosRet); // needed for the subtract-fee-from-amount feature + void reassignAmounts(const std::vector& out_amounts, int nChangePosRet); // needed for the subtract-fee-from-amount feature private: QList recipients;