From e9d19e5138adf0f79ef1124dc1a2c3aa22f22426 Mon Sep 17 00:00:00 2001
From: Pasta <pasta@dashboost.org>
Date: Thu, 22 Nov 2018 23:03:50 -0600
Subject: [PATCH 1/6] Implement optional CoinControl for gobject prepare

---
 src/rpc/governance.cpp | 23 ++++++++++++++++++++---
 src/wallet/wallet.cpp  | 10 +++++++---
 src/wallet/wallet.h    |  2 +-
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp
index 7c9e7f45a5e8..5eb02f22f290 100644
--- a/src/rpc/governance.cpp
+++ b/src/rpc/governance.cpp
@@ -133,12 +133,15 @@ void gobject_prepare_help()
                 "3. time          (numeric, required) time this object was created\n"
                 "4. data-hex      (string, required)  data in hex string form\n"
                 "5. use-IS        (boolean, optional, default=false) InstantSend lock the collateral, only requiring one chain confirmation\n"
+                "6. outputHash    (string, optional) the single output to submit the fee from\n"
+                "7. outputIndex   (numeric, optional) The output index.\n"
                 );
+    );
 }
 
 UniValue gobject_prepare(const JSONRPCRequest& request)
 {
-    if (request.fHelp || (request.params.size() != 5 && request.params.size() != 6)) 
+    if (request.fHelp || (request.params.size() != 5 && request.params.size() != 6 && request.params.size() != 8)) 
         gobject_prepare_help();
 
     if (!EnsureWalletIsAvailable(request.fHelp))
@@ -199,9 +202,23 @@ UniValue gobject_prepare(const JSONRPCRequest& request)
 
     EnsureWalletIsUnlocked();
 
+    // If specified, spend this outpoint as the fee
+    COutPoint outpoint;
+    outpoint.SetNull();
+    if (request.params.size() == 8) {
+        uint256 collateralHash = ParseHashV(request.params[6], "outputHash");
+        int32_t collateralIndex = ParseInt32V(request.params[7], "outputIndex");
+        if (collateralHash.IsNull() || collateralIndex < 0) {
+            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid hash or index: %s-%d", collateralHash.ToString(), collateralIndex));
+        }
+        outpoint = COutPoint(collateralHash, (uint32_t)collateralIndex);
+    }
+
     CWalletTx wtx;
-    if (!pwalletMain->GetBudgetSystemCollateralTX(wtx, govobj.GetHash(), govobj.GetMinCollateralFee(), useIS)) {
-        throw JSONRPCError(RPC_INTERNAL_ERROR, "Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked.");
+    if (!pwalletMain->GetBudgetSystemCollateralTX(wtx, govobj.GetHash(), govobj.GetMinCollateralFee(), useIS, outpoint)) {
+        std::string err = "Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked.";
+        if (request.params.size() == 7) err += "Please verify your specified output is valid and is enough for the combined proposal fee and transaction fee.";
+        throw JSONRPCError(RPC_INTERNAL_ERROR, err);
     }
 
     // -- make our change address
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ca9b51d1e41a..39f3502cc18c 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3356,7 +3356,7 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std
     return true;
 }
 
-bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend)
+bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, COutPoint outpoint)
 {
     // make our change address
     CReserveKey reservekey(this);
@@ -3370,8 +3370,12 @@ bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount a
     std::vector< CRecipient > vecSend;
     vecSend.push_back((CRecipient){scriptChange, amount, false});
 
-    CCoinControl *coinControl=NULL;
-    bool success = CreateTransaction(vecSend, tx, reservekey, nFeeRet, nChangePosRet, strFail, coinControl, true, ALL_COINS, fUseInstantSend);
+    CCoinControl coinControl;
+    coinControl.SetNull();
+    if (!outpoint.IsNull()) {
+        coinControl.Select(outpoint);
+    }
+    bool success = CreateTransaction(vecSend, tx, reservekey, nFeeRet, nChangePosRet, strFail, &coinControl, true, ALL_COINS, fUseInstantSend);
     if(!success){
         LogPrintf("CWallet::GetBudgetSystemCollateralTX -- Error: %s\n", strFail);
         return false;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index d17e8e957490..f97500f61205 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -922,7 +922,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
     CAmount GetNeedsToBeAnonymizedBalance(CAmount nMinBalance = 0) const;
     CAmount GetDenominatedBalance(bool unconfirmed=false) const;
 
-    bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend);
+    bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, COutPoint outpoint=COutPoint()/*defaults null*/);
 
     /**
      * Insert additional inputs into the transaction by

From 50f5adf068e18ee66cddfb80cd05383efc376bca Mon Sep 17 00:00:00 2001
From: UdjinM6 <UdjinM6@users.noreply.github.com>
Date: Mon, 26 Nov 2018 16:54:20 -0600
Subject: [PATCH 2/6] Removes duplicate `);` from merge error

Co-Authored-By: PastaPastaPasta <pasta@dashboost.org>
---
 src/rpc/governance.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp
index 5eb02f22f290..0301dd3dd715 100644
--- a/src/rpc/governance.cpp
+++ b/src/rpc/governance.cpp
@@ -136,7 +136,6 @@ void gobject_prepare_help()
                 "6. outputHash    (string, optional) the single output to submit the fee from\n"
                 "7. outputIndex   (numeric, optional) The output index.\n"
                 );
-    );
 }
 
 UniValue gobject_prepare(const JSONRPCRequest& request)

From c510880e7584a64a453e9b392b90ee7937423abf Mon Sep 17 00:00:00 2001
From: Paul <Paul@Laptop>
Date: Mon, 26 Nov 2018 16:57:58 -0600
Subject: [PATCH 3/6] Fix equality check allowing more relevant help output

---
 src/rpc/governance.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp
index 0301dd3dd715..97cc38452336 100644
--- a/src/rpc/governance.cpp
+++ b/src/rpc/governance.cpp
@@ -216,7 +216,7 @@ UniValue gobject_prepare(const JSONRPCRequest& request)
     CWalletTx wtx;
     if (!pwalletMain->GetBudgetSystemCollateralTX(wtx, govobj.GetHash(), govobj.GetMinCollateralFee(), useIS, outpoint)) {
         std::string err = "Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked.";
-        if (request.params.size() == 7) err += "Please verify your specified output is valid and is enough for the combined proposal fee and transaction fee.";
+        if (request.params.size() == 8) err += "Please verify your specified output is valid and is enough for the combined proposal fee and transaction fee.";
         throw JSONRPCError(RPC_INTERNAL_ERROR, err);
     }
 

From bfab0972d3a899f1c4269d32be8a4ef67da20cb6 Mon Sep 17 00:00:00 2001
From: UdjinM6 <UdjinM6@users.noreply.github.com>
Date: Mon, 26 Nov 2018 17:30:26 -0600
Subject: [PATCH 4/6] Pass COutPoint as const reference

Co-Authored-By: PastaPastaPasta <pasta@dashboost.org>
---
 src/wallet/wallet.cpp | 2 +-
 src/wallet/wallet.h   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 39f3502cc18c..f05097a16e5f 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3356,7 +3356,7 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std
     return true;
 }
 
-bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, COutPoint outpoint)
+bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, const COutPoint& outpoint)
 {
     // make our change address
     CReserveKey reservekey(this);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index f97500f61205..2e07ac69f89e 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -922,7 +922,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
     CAmount GetNeedsToBeAnonymizedBalance(CAmount nMinBalance = 0) const;
     CAmount GetDenominatedBalance(bool unconfirmed=false) const;
 
-    bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, COutPoint outpoint=COutPoint()/*defaults null*/);
+    bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, const COutPoint& outpoint=COutPoint()/*defaults null*/);
 
     /**
      * Insert additional inputs into the transaction by

From 1ed0ae8d753bec3b1d89272917da538adaea8c28 Mon Sep 17 00:00:00 2001
From: Alexander Block <ablock84@gmail.com>
Date: Tue, 27 Nov 2018 08:31:40 -0600
Subject: [PATCH 5/6] Remove unnecessary SetNull call

Co-Authored-By: PastaPastaPasta <pasta@dashboost.org>
---
 src/wallet/wallet.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index f05097a16e5f..f1bb0b4ccec4 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3371,7 +3371,6 @@ bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount a
     vecSend.push_back((CRecipient){scriptChange, amount, false});
 
     CCoinControl coinControl;
-    coinControl.SetNull();
     if (!outpoint.IsNull()) {
         coinControl.Select(outpoint);
     }

From 8598ff00db0786cd1994fd69c751c321b8f88f6a Mon Sep 17 00:00:00 2001
From: UdjinM6 <UdjinM6@users.noreply.github.com>
Date: Tue, 27 Nov 2018 11:08:42 -0600
Subject: [PATCH 6/6] Specify proposal fee

Co-Authored-By: PastaPastaPasta <pasta@dashboost.org>
---
 src/rpc/governance.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp
index 97cc38452336..704582f49940 100644
--- a/src/rpc/governance.cpp
+++ b/src/rpc/governance.cpp
@@ -133,7 +133,7 @@ void gobject_prepare_help()
                 "3. time          (numeric, required) time this object was created\n"
                 "4. data-hex      (string, required)  data in hex string form\n"
                 "5. use-IS        (boolean, optional, default=false) InstantSend lock the collateral, only requiring one chain confirmation\n"
-                "6. outputHash    (string, optional) the single output to submit the fee from\n"
+                "6. outputHash    (string, optional) the single output to submit the proposal fee from\n"
                 "7. outputIndex   (numeric, optional) The output index.\n"
                 );
 }
@@ -201,7 +201,7 @@ UniValue gobject_prepare(const JSONRPCRequest& request)
 
     EnsureWalletIsUnlocked();
 
-    // If specified, spend this outpoint as the fee
+    // If specified, spend this outpoint as the proposal fee
     COutPoint outpoint;
     outpoint.SetNull();
     if (request.params.size() == 8) {
