diff options
Diffstat (limited to 'src/qt')
| -rw-r--r-- | src/qt/addresstablemodel.cpp | 2 | ||||
| -rw-r--r-- | src/qt/askpassphrasedialog.cpp | 2 | ||||
| -rw-r--r-- | src/qt/bitcoin.cpp | 2 | ||||
| -rw-r--r-- | src/qt/bitcoingui.cpp | 2 | ||||
| -rw-r--r-- | src/qt/coincontroldialog.cpp | 25 | ||||
| -rw-r--r-- | src/qt/coincontroldialog.h | 1 | ||||
| -rw-r--r-- | src/qt/forms/sendcoinsentry.ui | 16 | ||||
| -rw-r--r-- | src/qt/macdockiconhandler.h | 9 | ||||
| -rw-r--r-- | src/qt/macdockiconhandler.mm | 61 | ||||
| -rw-r--r-- | src/qt/optionsdialog.cpp | 2 | ||||
| -rw-r--r-- | src/qt/optionsmodel.cpp | 4 | ||||
| -rw-r--r-- | src/qt/paymentserver.cpp | 2 | ||||
| -rw-r--r-- | src/qt/sendcoinsdialog.cpp | 70 | ||||
| -rw-r--r-- | src/qt/sendcoinsentry.cpp | 6 | ||||
| -rw-r--r-- | src/qt/sendcoinsentry.h | 1 | ||||
| -rw-r--r-- | src/qt/signverifymessagedialog.cpp | 2 | ||||
| -rw-r--r-- | src/qt/splashscreen.cpp | 2 | ||||
| -rw-r--r-- | src/qt/transactiondesc.cpp | 4 | ||||
| -rw-r--r-- | src/qt/transactionrecord.cpp | 2 | ||||
| -rw-r--r-- | src/qt/transactiontablemodel.cpp | 2 | ||||
| -rw-r--r-- | src/qt/walletmodel.cpp | 28 | ||||
| -rw-r--r-- | src/qt/walletmodel.h | 8 | ||||
| -rw-r--r-- | src/qt/walletmodeltransaction.cpp | 34 | ||||
| -rw-r--r-- | src/qt/walletmodeltransaction.h | 4 |
24 files changed, 184 insertions, 107 deletions
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 162ecdba4..9573fe43d 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -8,7 +8,7 @@ #include "walletmodel.h" #include "base58.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <QFont> #include <QDebug> diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 9b7b59c0d..229139e65 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -8,7 +8,7 @@ #include "guiconstants.h" #include "walletmodel.h" -#include "allocators.h" +#include "support/allocators/secure.h" #include <QKeyEvent> #include <QMessageBox> diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 73c684e48..3ae780abf 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -30,7 +30,7 @@ #include "util.h" #ifdef ENABLE_WALLET -#include "wallet.h" +#include "wallet/wallet.h" #endif #include <stdint.h> diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 1ec968ff2..58c005ae7 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -237,7 +237,7 @@ BitcoinGUI::~BitcoinGUI() trayIcon->hide(); #ifdef Q_OS_MAC delete appMenuBar; - MacDockIconHandler::instance()->setMainWindow(NULL); + MacDockIconHandler::cleanup(); #endif delete rpcConsole; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 3f4f082b8..e4e9015c8 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -15,7 +15,7 @@ #include "coincontrol.h" #include "main.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <boost/assign/list_of.hpp> // for 'map_list_of()' @@ -33,6 +33,7 @@ using namespace std; QList<CAmount> CoinControlDialog::payAmounts; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); +bool CoinControlDialog::fSubtractFeeFromAmount = false; CoinControlDialog::CoinControlDialog(QWidget *parent) : QDialog(parent), @@ -541,6 +542,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority) sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority); + // in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate + if (CoinControlDialog::fSubtractFeeFromAmount) + if (nAmount - nPayAmount == 0) + nBytes -= 34; + // Fee nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool); @@ -556,7 +562,9 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) if (nPayAmount > 0) { - nChange = nAmount - nPayFee - nPayAmount; + nChange = nAmount - nPayAmount; + if (!CoinControlDialog::fSubtractFeeFromAmount) + nChange -= nPayFee; // Never create dust outputs; if we would, just add the dust to the fee. if (nChange > 0 && nChange < CENT) @@ -564,12 +572,17 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) CTxOut txout(nChange, (CScript)vector<unsigned char>(24, 0)); if (txout.IsDust(::minRelayTxFee)) { - nPayFee += nChange; - nChange = 0; + if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust + nChange = txout.GetDustThreshold(::minRelayTxFee); + else + { + nPayFee += nChange; + nChange = 0; + } } } - if (nChange == 0) + if (nChange == 0 && !CoinControlDialog::fSubtractFeeFromAmount) nBytes -= 34; } @@ -612,7 +625,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { l3->setText(ASYMP_UTF8 + l3->text()); l4->setText(ASYMP_UTF8 + l4->text()); - if (nChange > 0) + if (nChange > 0 && !CoinControlDialog::fSubtractFeeFromAmount) l8->setText(ASYMP_UTF8 + l8->text()); } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 5a91876f1..5ec382838 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -43,6 +43,7 @@ public: static QList<CAmount> payAmounts; static CCoinControl *coinControl; + static bool fSubtractFeeFromAmount; private: Ui::CoinControlDialog *ui; diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index 9f8c0a484..b36292843 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -157,7 +157,21 @@ </widget> </item> <item row="2" column="1"> - <widget class="BitcoinAmountField" name="payAmount"/> + <layout class="QHBoxLayout" name="horizontalLayoutAmount" stretch="0,1"> + <item> + <widget class="BitcoinAmountField" name="payAmount"/> + </item> + <item> + <widget class="QCheckBox" name="checkboxSubtractFeeFromAmount"> + <property name="toolTip"> + <string>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</string> + </property> + <property name="text"> + <string>S&ubtract fee from amount</string> + </property> + </widget> + </item> + </layout> </item> <item row="3" column="0"> <widget class="QLabel" name="messageLabel"> diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h index 1217bd8e8..15a6583ca 100644 --- a/src/qt/macdockiconhandler.h +++ b/src/qt/macdockiconhandler.h @@ -14,12 +14,6 @@ class QMenu; class QWidget; QT_END_NAMESPACE -#ifdef __OBJC__ -@class DockIconClickEventHandler; -#else -class DockIconClickEventHandler; -#endif - /** Macintosh-specific dock icon handler. */ class MacDockIconHandler : public QObject @@ -33,7 +27,7 @@ public: void setIcon(const QIcon &icon); void setMainWindow(QMainWindow *window); static MacDockIconHandler *instance(); - + static void cleanup(); void handleDockIconClickEvent(); signals: @@ -42,7 +36,6 @@ signals: private: MacDockIconHandler(); - DockIconClickEventHandler *m_dockIconClickEventHandler; QWidget *m_dummyWidget; QMenu *m_dockMenu; QMainWindow *mainWindow; diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index e7b58b9cc..58a0365d3 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -11,52 +11,46 @@ #undef slots #include <Cocoa/Cocoa.h> +#include <objc/objc.h> +#include <objc/message.h> #if QT_VERSION < 0x050000 extern void qt_mac_set_dock_menu(QMenu *); #endif -@interface DockIconClickEventHandler : NSObject -{ - MacDockIconHandler* dockIconHandler; -} - -@end +static MacDockIconHandler *s_instance = NULL; -@implementation DockIconClickEventHandler - -- (id)initWithDockIconHandler:(MacDockIconHandler *)aDockIconHandler -{ - self = [super init]; - if (self) { - dockIconHandler = aDockIconHandler; - - [[NSAppleEventManager sharedAppleEventManager] - setEventHandler:self - andSelector:@selector(handleDockClickEvent:withReplyEvent:) - forEventClass:kCoreEventClass - andEventID:kAEReopenApplication]; - } - return self; +bool dockClickHandler(id self,SEL _cmd,...) { + Q_UNUSED(self) + Q_UNUSED(_cmd) + + s_instance->handleDockIconClickEvent(); + + // Return NO (false) to suppress the default OS X actions + return false; } -- (void)handleDockClickEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent -{ - Q_UNUSED(event) - Q_UNUSED(replyEvent) - - if (dockIconHandler) { - dockIconHandler->handleDockIconClickEvent(); +void setupDockClickHandler() { + Class cls = objc_getClass("NSApplication"); + id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication")); + + if (appInst != NULL) { + id delegate = objc_msgSend(appInst, sel_registerName("delegate")); + Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class")); + SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"); + if (class_getInstanceMethod(delClass, shouldHandle)) + class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"); + else + class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:"); } } -@end MacDockIconHandler::MacDockIconHandler() : QObject() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this]; + setupDockClickHandler(); this->m_dummyWidget = new QWidget(); this->m_dockMenu = new QMenu(this->m_dummyWidget); this->setMainWindow(NULL); @@ -74,7 +68,6 @@ void MacDockIconHandler::setMainWindow(QMainWindow *window) { MacDockIconHandler::~MacDockIconHandler() { - [this->m_dockIconClickEventHandler release]; delete this->m_dummyWidget; this->setMainWindow(NULL); } @@ -119,12 +112,16 @@ void MacDockIconHandler::setIcon(const QIcon &icon) MacDockIconHandler *MacDockIconHandler::instance() { - static MacDockIconHandler *s_instance = NULL; if (!s_instance) s_instance = new MacDockIconHandler(); return s_instance; } +void MacDockIconHandler::cleanup() +{ + delete s_instance; +} + void MacDockIconHandler::handleDockIconClickEvent() { if (this->mainWindow) diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index a342b4bfe..a9e4b339e 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -18,7 +18,7 @@ #include "txdb.h" // for -dbcache defaults #ifdef ENABLE_WALLET -#include "wallet.h" // for CWallet::minTxFee +#include "wallet/wallet.h" // for CWallet::minTxFee #endif #include <boost/thread.hpp> diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 7d2dbd96d..a169ed6b5 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -18,8 +18,8 @@ #include "txdb.h" // for -dbcache defaults #ifdef ENABLE_WALLET -#include "wallet.h" -#include "walletdb.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" #endif #include <QNetworkProxy> diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 96ceeb18a..40d6e16f5 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -12,7 +12,7 @@ #include "chainparams.h" #include "ui_interface.h" #include "util.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <cstdlib> diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 4f3230a8c..28c8fb95f 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -18,7 +18,7 @@ #include "base58.h" #include "coincontrol.h" #include "ui_interface.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <QMessageBox> #include <QScrollBar> @@ -220,9 +220,37 @@ void SendCoinsDialog::on_sendButton_clicked() return; } + fNewRecipientAllowed = false; + WalletModel::UnlockContext ctx(model->requestUnlock()); + if(!ctx.isValid()) + { + // Unlock wallet was cancelled + fNewRecipientAllowed = true; + return; + } + + // prepare transaction for getting txFee earlier + WalletModelTransaction currentTransaction(recipients); + WalletModel::SendCoinsReturn prepareStatus; + if (model->getOptionsModel()->getCoinControlFeatures()) // coin control enabled + prepareStatus = model->prepareTransaction(currentTransaction, CoinControlDialog::coinControl); + else + prepareStatus = model->prepareTransaction(currentTransaction); + + // process prepareStatus and on error generate message shown to user + processSendCoinsReturn(prepareStatus, + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee())); + + if(prepareStatus.status != WalletModel::OK) { + fNewRecipientAllowed = true; + return; + } + + CAmount txFee = currentTransaction.getTransactionFee(); + // Format confirmation message QStringList formatted; - foreach(const SendCoinsRecipient &rcp, recipients) + foreach(const SendCoinsRecipient &rcp, currentTransaction.getRecipients()) { // generate bold amount string QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); @@ -257,35 +285,6 @@ void SendCoinsDialog::on_sendButton_clicked() formatted.append(recipientElement); } - fNewRecipientAllowed = false; - - - WalletModel::UnlockContext ctx(model->requestUnlock()); - if(!ctx.isValid()) - { - // Unlock wallet was cancelled - fNewRecipientAllowed = true; - return; - } - - // prepare transaction for getting txFee earlier - WalletModelTransaction currentTransaction(recipients); - WalletModel::SendCoinsReturn prepareStatus; - if (model->getOptionsModel()->getCoinControlFeatures()) // coin control enabled - prepareStatus = model->prepareTransaction(currentTransaction, CoinControlDialog::coinControl); - else - prepareStatus = model->prepareTransaction(currentTransaction); - - // process prepareStatus and on error generate message shown to user - processSendCoinsReturn(prepareStatus, - BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee())); - - if(prepareStatus.status != WalletModel::OK) { - fNewRecipientAllowed = true; - return; - } - - CAmount txFee = currentTransaction.getTransactionFee(); QString questionString = tr("Are you sure you want to send?"); questionString.append("<br /><br />%1"); @@ -368,6 +367,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry() ui->entries->addWidget(entry); connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*))); connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels())); + connect(entry, SIGNAL(subtractFeeFromAmountChanged()), this, SLOT(coinControlUpdateLabels())); updateTabsAndLabels(); @@ -783,11 +783,17 @@ void SendCoinsDialog::coinControlUpdateLabels() // set pay amounts CoinControlDialog::payAmounts.clear(); + CoinControlDialog::fSubtractFeeFromAmount = false; for(int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget()); if(entry) - CoinControlDialog::payAmounts.append(entry->getValue().amount); + { + SendCoinsRecipient rcp = entry->getValue(); + CoinControlDialog::payAmounts.append(rcp.amount); + if (rcp.fSubtractFeeFromAmount) + CoinControlDialog::fSubtractFeeFromAmount = true; + } } if (CoinControlDialog::coinControl->HasSelected()) diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 6db6eee75..6ac650e74 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -44,6 +44,7 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) : // Connect signals connect(ui->payAmount, SIGNAL(valueChanged()), this, SIGNAL(payAmountChanged())); + connect(ui->checkboxSubtractFeeFromAmount, SIGNAL(toggled(bool)), this, SIGNAL(subtractFeeFromAmountChanged())); connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked())); connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked())); connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked())); @@ -94,6 +95,7 @@ void SendCoinsEntry::clear() ui->payTo->clear(); ui->addAsLabel->clear(); ui->payAmount->clear(); + ui->checkboxSubtractFeeFromAmount->setCheckState(Qt::Unchecked); ui->messageTextLabel->clear(); ui->messageTextLabel->hide(); ui->messageLabel->hide(); @@ -165,6 +167,7 @@ SendCoinsRecipient SendCoinsEntry::getValue() recipient.label = ui->addAsLabel->text(); recipient.amount = ui->payAmount->value(); recipient.message = ui->messageTextLabel->text(); + recipient.fSubtractFeeFromAmount = (ui->checkboxSubtractFeeFromAmount->checkState() == Qt::Checked); return recipient; } @@ -174,7 +177,8 @@ QWidget *SendCoinsEntry::setupTabChain(QWidget *prev) QWidget::setTabOrder(prev, ui->payTo); QWidget::setTabOrder(ui->payTo, ui->addAsLabel); QWidget *w = ui->payAmount->setupTabChain(ui->addAsLabel); - QWidget::setTabOrder(w, ui->addressBookButton); + QWidget::setTabOrder(w, ui->checkboxSubtractFeeFromAmount); + QWidget::setTabOrder(ui->checkboxSubtractFeeFromAmount, ui->addressBookButton); QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton); QWidget::setTabOrder(ui->pasteButton, ui->deleteButton); return ui->deleteButton; diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index 4cb00cd36..c2d1185bd 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -51,6 +51,7 @@ public slots: signals: void removeEntry(SendCoinsEntry *entry); void payAmountChanged(); + void subtractFeeFromAmountChanged(); private slots: void deleteClicked(); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 970f6a520..76da6904a 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -12,7 +12,7 @@ #include "base58.h" #include "init.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <string> #include <vector> diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index e6a7fcaec..414fe02ff 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -12,7 +12,7 @@ #include "version.h" #ifdef ENABLE_WALLET -#include "wallet.h" +#include "wallet/wallet.h" #endif #include <QApplication> diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 68c275d49..9b235f913 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -10,13 +10,13 @@ #include "transactionrecord.h" #include "base58.h" -#include "db.h" +#include "wallet/db.h" #include "main.h" #include "script/script.h" #include "timedata.h" #include "ui_interface.h" #include "util.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <stdint.h> #include <string> diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index fea436806..19e3fc0dc 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -6,7 +6,7 @@ #include "base58.h" #include "timedata.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <stdint.h> diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index df1afbfaa..dff2676b1 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -17,7 +17,7 @@ #include "sync.h" #include "uint256.h" #include "util.h" -#include "wallet.h" +#include "wallet/wallet.h" #include <QColor> #include <QDateTime> diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 79f5191fc..09ed8ce9f 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -6,18 +6,19 @@ #include "addresstablemodel.h" #include "guiconstants.h" +#include "guiutil.h" #include "paymentserver.h" #include "recentrequeststablemodel.h" #include "transactiontablemodel.h" #include "base58.h" -#include "db.h" +#include "wallet/db.h" #include "keystore.h" #include "main.h" #include "sync.h" #include "ui_interface.h" -#include "wallet.h" -#include "walletdb.h" // for BackupWallet +#include "wallet/wallet.h" +#include "wallet/walletdb.h" // for BackupWallet #include <stdint.h> @@ -192,8 +193,9 @@ bool WalletModel::validateAddress(const QString &address) WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl) { CAmount total = 0; + bool fSubtractFeeFromAmount = false; QList<SendCoinsRecipient> recipients = transaction.getRecipients(); - std::vector<std::pair<CScript, CAmount> > vecSend; + std::vector<CRecipient> vecSend; if(recipients.empty()) { @@ -206,6 +208,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { + if (rcp.fSubtractFeeFromAmount) + fSubtractFeeFromAmount = true; + if (rcp.paymentRequest.IsInitialized()) { // PaymentRequest... CAmount subtotal = 0; @@ -217,7 +222,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact subtotal += out.amount(); const unsigned char* scriptStr = (const unsigned char*)out.script().data(); CScript scriptPubKey(scriptStr, scriptStr+out.script().size()); - vecSend.push_back(std::pair<CScript, CAmount>(scriptPubKey, out.amount())); + CAmount nAmount = out.amount(); + CRecipient recipient = {scriptPubKey, nAmount, rcp.fSubtractFeeFromAmount}; + vecSend.push_back(recipient); } if (subtotal <= 0) { @@ -239,7 +246,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact ++nAddresses; CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); - vecSend.push_back(std::pair<CScript, CAmount>(scriptPubKey, rcp.amount)); + CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount}; + vecSend.push_back(recipient); total += rcp.amount; } @@ -260,17 +268,21 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact LOCK2(cs_main, wallet->cs_wallet); transaction.newPossibleKeyChange(wallet); + CAmount nFeeRequired = 0; + int nChangePosRet = -1; std::string strFailReason; CWalletTx *newTx = transaction.getTransaction(); CReserveKey *keyChange = transaction.getPossibleKeyChange(); - bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, strFailReason, coinControl); + bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl); transaction.setTransactionFee(nFeeRequired); + if (fSubtractFeeFromAmount && fCreated) + transaction.reassignAmounts(nChangePosRet); if(!fCreated) { - if((total + nFeeRequired) > nBalance) + if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance); } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 4a9a12bea..e26343888 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -8,7 +8,7 @@ #include "paymentrequestplus.h" #include "walletmodeltransaction.h" -#include "allocators.h" /* for SecureString */ +#include "support/allocators/secure.h" #include <map> #include <vector> @@ -36,9 +36,9 @@ QT_END_NAMESPACE class SendCoinsRecipient { public: - explicit SendCoinsRecipient() : amount(0), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } + explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message): - address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} + address(addr), label(label), amount(amount), message(message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} // If from an unauthenticated payment request, this is used for storing // the addresses, e.g. address-A<br />address-B<br />address-C. @@ -56,6 +56,8 @@ public: // Empty if no authentication or invalid signature/cert/etc. QString authenticatedMerchant; + bool fSubtractFeeFromAmount; // memory only + static const int CURRENT_VERSION = 1; int nVersion; diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 8f32e4614..206bb7c77 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -4,7 +4,7 @@ #include "walletmodeltransaction.h" -#include "wallet.h" +#include "wallet/wallet.h" WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &recipients) : recipients(recipients), @@ -46,6 +46,38 @@ void WalletModelTransaction::setTransactionFee(const CAmount& newFee) fee = newFee; } +void WalletModelTransaction::reassignAmounts(int nChangePosRet) +{ + int i = 0; + for (QList<SendCoinsRecipient>::iterator it = recipients.begin(); it != recipients.end(); ++it) + { + SendCoinsRecipient& rcp = (*it); + + if (rcp.paymentRequest.IsInitialized()) + { + CAmount subtotal = 0; + const payments::PaymentDetails& details = rcp.paymentRequest.getDetails(); + for (int j = 0; j < details.outputs_size(); j++) + { + const payments::Output& out = details.outputs(j); + if (out.amount() <= 0) continue; + if (i == nChangePosRet) + i++; + subtotal += walletTransaction->vout[i].nValue; + i++; + } + rcp.amount = subtotal; + } + else // normal recipient (no payment request) + { + if (i == nChangePosRet) + i++; + rcp.amount = walletTransaction->vout[i].nValue; + i++; + } + } +} + CAmount WalletModelTransaction::getTotalTransactionAmount() { CAmount totalTransactionAmount = 0; diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index b6bb6d67f..7765fea4a 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -35,8 +35,10 @@ public: void newPossibleKeyChange(CWallet *wallet); CReserveKey *getPossibleKeyChange(); + void reassignAmounts(int nChangePosRet); // needed for the subtract-fee-from-amount feature + private: - const QList<SendCoinsRecipient> recipients; + QList<SendCoinsRecipient> recipients; CWalletTx *walletTransaction; CReserveKey *keyChange; CAmount fee; |