text: // Copyright (c) 2010 Satoshi Nakamoto
  // Copyright (c) 2009-2014 The Bitcoin developers
  // Copyright (c) 2014-2015 The Dash developers
  // Copyright (c) 2015-2020 The HodlCash developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #include "base58.h"
  #include "core_io.h"
  #include "init.h"
  #include "keystore.h"
  #include "main.h"
  #include "net.h"
  #include "primitives/transaction.h"
  #include "zpiv/deterministicmint.h"
  #include "rpc/server.h"
  #include "script/script.h"
  #include "script/script_error.h"
  #include "script/sign.h"
  #include "script/standard.h"
  #include "swifttx.h"
  #include "uint256.h"
  #include "utilmoneystr.h"
  #include "zpivchain.h"
  #ifdef ENABLE_WALLET
  #include "wallet/wallet.h"
  #endif
  
  #include <stdint.h>
  
  #include <boost/assign/list_of.hpp>
  
  #include <univalue.h>
  
  
  void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
  {
      txnouttype type;
      std::vector<CTxDestination> addresses;
      int nRequired;
  
      out.push_back(Pair("asm", scriptPubKey.ToString()));
      if (fIncludeHex)
          out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
  
      if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
          out.push_back(Pair("type", GetTxnOutputType(type)));
          return;
      }
  
      out.push_back(Pair("reqSigs", nRequired));
      out.push_back(Pair("type", GetTxnOutputType(type)));
  
      UniValue a(UniValue::VARR);
      for (const CTxDestination& addr : addresses)
          a.push_back(CBitcoinAddress(addr).ToString());
      out.push_back(Pair("addresses", a));
  }
  
  void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
  {
      // Call into TxToUniv() in bitcoin-common to decode the transaction hex.
      //
      // Blockchain contextual information (confirmations and blocktime) is not
      // available to code in bitcoin-common, so we query them here and push the
      // data into the returned UniValue.
      TxToUniv(tx, uint256(), entry);
  
      if (!hashBlock.IsNull()) {
          entry.push_back(Pair("blockhash", hashBlock.GetHex()));
          BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
          if (mi != mapBlockIndex.end() && (*mi).second) {
              CBlockIndex* pindex = (*mi).second;
              if (chainActive.Contains(pindex)) {
                  entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
                  entry.push_back(Pair("time", pindex->GetBlockTime()));
                  entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
              }
              else
                  entry.push_back(Pair("confirmations", 0));
          }
      }
  }
  
  UniValue getrawtransaction(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() < 1 || params.size() > 3)
          throw std::runtime_error(
              "getrawtransaction \"txid\" ( verbose \"blockhash\" )\n"
  
              "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
              "or there is an unspent output in the utxo for this transaction. To make it always work,\n"
              "you need to maintain a transaction index, using the -txindex command line option.\n"
  
              "\nReturn the raw transaction data.\n"
              "\nIf verbose is 'true', returns an Object with information about 'txid'.\n"
              "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n"
  
              "\nArguments:\n"
              "1. \"txid\"      (string, required) The transaction id\n"
              "2. verbose     (bool, optional, default=false) If false, return a string, otherwise return a json object\n"
              "3. \"blockhash\" (string, optional) The block in which to look for the transaction\n"
  
              "\nResult (if verbose is not set or set to false):\n"
              "\"data\"      (string) The serialized, hex-encoded data for 'txid'\n"
  
              "\nResult (if verbose is set to true):\n"
              "{\n"
              "  \"in_active_chain\": b, (bool) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n"
              "  \"hex\" : \"data\",       (string) The serialized, hex-encoded data for 'txid'\n"
              "  \"txid\" : \"id\",        (string) The transaction id (same as provided)\n"
              "  \"size\" : n,             (numeric) The serialized transaction size\n"
              "  \"version\" : n,          (numeric) The version\n"
              "  \"locktime\" : ttt,       (numeric) The lock time\n"
              "  \"vin\" : [               (array of json objects)\n"
              "     {\n"
              "       \"txid\": \"id\",    (string) The transaction id\n"
              "       \"vout\": n,         (numeric) \n"
              "       \"scriptSig\": {     (json object) The script\n"
              "         \"asm\": \"asm\",  (string) asm\n"
              "         \"hex\": \"hex\"   (string) hex\n"
              "       },\n"
              "       \"sequence\": n      (numeric) The script sequence number\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "  \"vout\" : [              (array of json objects)\n"
              "     {\n"
              "       \"value\" : x.xxx,            (numeric) The value in btc\n"
              "       \"n\" : n,                    (numeric) index\n"
              "       \"scriptPubKey\" : {          (json object)\n"
              "         \"asm\" : \"asm\",          (string) the asm\n"
              "         \"hex\" : \"hex\",          (string) the hex\n"
              "         \"reqSigs\" : n,            (numeric) The required sigs\n"
              "         \"type\" : \"pubkeyhash\",  (string) The type, eg 'pubkeyhash'\n"
              "         \"addresses\" : [           (json array of string)\n"
              "           \"hodlcashaddress\"        (string) hodlcash address\n"
              "           ,...\n"
              "         ]\n"
              "       }\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "  \"blockhash\" : \"hash\",   (string) the block hash\n"
              "  \"confirmations\" : n,      (numeric) The confirmations\n"
              "  \"time\" : ttt,             (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\n"
              "  \"blocktime\" : ttt         (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
              "}\n"
  
              "\nExamples:\n"
              + HelpExampleCli("getrawtransaction", "\"mytxid\"")
              + HelpExampleCli("getrawtransaction", "\"mytxid\" true")
              + HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
              + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
              + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
          );
  
      LOCK(cs_main);
  
      bool in_active_chain = true;
      uint256 hash = ParseHashV(params[0], "parameter 1");
      CBlockIndex* blockindex = nullptr;
  
      bool fVerbose = false;
      if (!params[1].isNull()) {
          fVerbose = params[1].isNum() ? (params[1].get_int() != 0) : params[1].get_bool();
      }
  
      if (!params[2].isNull()) {
          uint256 blockhash = ParseHashV(params[2], "parameter 3");
          BlockMap::iterator it = mapBlockIndex.find(blockhash);
          if (it == mapBlockIndex.end()) {
              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
          }
          blockindex = it->second;
          in_active_chain = chainActive.Contains(blockindex);
      }
  
      CTransaction tx;
      uint256 hash_block;
      if (!GetTransaction(hash, tx, hash_block, true, blockindex)) {
          std::string errmsg;
          if (blockindex) {
              if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) {
                  throw JSONRPCError(RPC_MISC_ERROR, "Block not available");
              }
              errmsg = "No such transaction found in the provided block";
          } else {
              errmsg = fTxIndex
                ? "No such mempool or blockchain transaction"
                : "No such mempool transaction. Use -txindex to enable blockchain transaction queries";
          }
          throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions.");
      }
  
      if (!fVerbose) {
          return EncodeHexTx(tx);
      }
  
      UniValue result(UniValue::VOBJ);
      if (blockindex) result.push_back(Pair("in_active_chain", in_active_chain));
      TxToJSON(tx, hash_block, result);
      return result;
  }
  
  #ifdef ENABLE_WALLET
  UniValue listunspent(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() > 4)
          throw std::runtime_error(
              "listunspent ( minconf maxconf  [\"address\",...] watchonlyconfig )\n"
              "\nReturns array of unspent transaction outputs\n"
              "with between minconf and maxconf (inclusive) confirmations.\n"
              "Optionally filter to only include txouts paid to specified addresses.\n"
              "Results are an array of Objects, each of which has:\n"
              "{txid, vout, scriptPubKey, amount, confirmations, spendable}\n"
  
              "\nArguments:\n"
              "1. minconf          (numeric, optional, default=1) The minimum confirmations to filter\n"
              "2. maxconf          (numeric, optional, default=9999999) The maximum confirmations to filter\n"
              "3. \"addresses\"    (string) A json array of hodlcash addresses to filter\n"
              "    [\n"
              "      \"address\"   (string) hodlcash address\n"
              "      ,...\n"
              "    ]\n"
              "4. watchonlyconfig  (numeric, optional, default=1) 1 = list regular unspent transactions, 2 = list only watchonly transactions,  3 = list all unspent transactions (including watchonly)\n"
  
              "\nResult\n"
              "[                   (array of json object)\n"
              "  {\n"
              "    \"txid\" : \"txid\",        (string) the transaction id\n"
              "    \"vout\" : n,               (numeric) the vout value\n"
              "    \"address\" : \"address\",  (string) the hodlcash address\n"
              "    \"account\" : \"account\",  (string) DEPRECATED. The associated account, or \"\" for the default account\n"
              "    \"scriptPubKey\" : \"key\", (string) the script key\n"
              "    \"redeemScript\" : \"key\", (string) the redeemscript key\n"
              "    \"amount\" : x.xxx,         (numeric) the transaction amount in btc\n"
              "    \"confirmations\" : n,      (numeric) The number of confirmations\n"
              "    \"spendable\" : true|false  (boolean) Whether we have the private keys to spend this output\n"
              "  }\n"
              "  ,...\n"
              "]\n"
  
              "\nExamples\n" +
              HelpExampleCli("listunspent", "") + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\""));
  
      RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR)(UniValue::VNUM));
  
      int nMinDepth = 1;
      if (params.size() > 0)
          nMinDepth = params[0].get_int();
  
      int nMaxDepth = 9999999;
      if (params.size() > 1)
          nMaxDepth = params[1].get_int();
  
      std::set<CBitcoinAddress> setAddress;
      if (params.size() > 2) {
          UniValue inputs = params[2].get_array();
          for (unsigned int inx = 0; inx < inputs.size(); inx++) {
              const UniValue& input = inputs[inx];
              CBitcoinAddress address(input.get_str());
              if (!address.IsValid())
                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid HodlCash address: ") + input.get_str());
              if (setAddress.count(address))
                  throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
              setAddress.insert(address);
          }
      }
  
      int nWatchonlyConfig = 1;
      if(params.size() > 3) {
          nWatchonlyConfig = params[3].get_int();
          if (nWatchonlyConfig > 3 || nWatchonlyConfig < 1)
              nWatchonlyConfig = 1;
      }
  
      UniValue results(UniValue::VARR);
      std::vector<COutput> vecOutputs;
      assert(pwalletMain != NULL);
      LOCK2(cs_main, pwalletMain->cs_wallet);
      pwalletMain->AvailableCoins(vecOutputs, false, NULL, false, ALL_COINS, false, nWatchonlyConfig);
      for (const COutput& out : vecOutputs) {
          if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
              continue;
  
          if (setAddress.size()) {
              CTxDestination address;
              if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
                  continue;
  
              if (!setAddress.count(address))
                  continue;
          }
  
          CAmount nValue = out.tx->vout[out.i].nValue;
          const CScript& pk = out.tx->vout[out.i].scriptPubKey;
          UniValue entry(UniValue::VOBJ);
          entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
          entry.push_back(Pair("vout", out.i));
          CTxDestination address;
          if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
              entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
              if (pwalletMain->mapAddressBook.count(address))
                  entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
          }
          entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
          if (pk.IsPayToScriptHash()) {
              CTxDestination address;
              if (ExtractDestination(pk, address)) {
                  const CScriptID& hash = boost::get<CScriptID>(address);
                  CScript redeemScript;
                  if (pwalletMain->GetCScript(hash, redeemScript))
                      entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
              }
          }
          entry.push_back(Pair("amount", ValueFromAmount(nValue)));
          entry.push_back(Pair("confirmations", out.nDepth));
          entry.push_back(Pair("spendable", out.fSpendable));
          results.push_back(entry);
      }
  
      return results;
  }
  #endif
  
  UniValue createrawtransaction(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() < 2 || params.size() > 3)
          throw std::runtime_error(
              "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...} ( locktime )\n"
              "\nCreate a transaction spending the given inputs and sending to the given addresses.\n"
              "Returns hex-encoded raw transaction.\n"
              "Note that the transaction's inputs are not signed, and\n"
              "it is not stored in the wallet or transmitted to the network.\n"
  
              "\nArguments:\n"
              "1. \"transactions\"        (string, required) A json array of json objects\n"
              "     [\n"
              "       {\n"
              "         \"txid\":\"id\",  (string, required) The transaction id\n"
              "         \"vout\":n,       (numeric, required) The output number\n"
              "         \"sequence\":n    (numeric, optional) The sequence number\n"
              "       }\n"
              "       ,...\n"
              "     ]\n"
              "2. \"addresses\"           (string, required) a json object with addresses as keys and amounts as values\n"
              "    {\n"
              "      \"address\": x.xxx   (numeric, required) The key is the hodlcash address, the value is the hodlcash amount\n"
              "      ,...\n"
              "    }\n"
              "3. locktime                (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
  
              "\nResult:\n"
              "\"transaction\"            (string) hex string of the transaction\n"
  
              "\nExamples\n" +
              HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\""));
  
      LOCK(cs_main);
      RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM));
      if (params[0].isNull() || params[1].isNull())
          throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
  
      UniValue inputs = params[0].get_array();
      UniValue sendTo = params[1].get_obj();
  
      CMutableTransaction rawTx;
  
      if (params.size() > 2 && !params[2].isNull()) {
          int64_t nLockTime = params[2].get_int64();
          if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
          rawTx.nLockTime = nLockTime;
      }
  
      for (unsigned int idx = 0; idx < inputs.size(); idx++) {
          const UniValue& input = inputs[idx];
          const UniValue& o = input.get_obj();
  
          uint256 txid = ParseHashO(o, "txid");
  
          const UniValue& vout_v = find_value(o, "vout");
          if (!vout_v.isNum())
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
          int nOutput = vout_v.get_int();
          if (nOutput < 0)
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
  
          uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max());
  
          // set the sequence number if passed in the parameters object
          const UniValue& sequenceObj = find_value(o, "sequence");
          if (sequenceObj.isNum()) {
              int64_t seqNr64 = sequenceObj.get_int64();
              if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max())
                  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
              else
                  nSequence = (uint32_t)seqNr64;
          }
  
          CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
  
          rawTx.vin.push_back(in);
      }
  
      std::set<CBitcoinAddress> setAddress;
      std::vector<std::string> addrList = sendTo.getKeys();
      for (const std::string& name_ : addrList) {
          CBitcoinAddress address(name_);
          if (!address.IsValid())
              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid HodlCash address: ")+name_);
  
          if (setAddress.count(address))
              throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
          setAddress.insert(address);
  
          CScript scriptPubKey = GetScriptForDestination(address.Get());
          CAmount nAmount = AmountFromValue(sendTo[name_]);
  
          CTxOut out(nAmount, scriptPubKey);
          rawTx.vout.push_back(out);
      }
  
      return EncodeHexTx(rawTx);
  }
  
  UniValue decoderawtransaction(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() != 1)
          throw std::runtime_error(
              "decoderawtransaction \"hexstring\"\n"
              "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
  
              "\nArguments:\n"
              "1. \"hex\"      (string, required) The transaction hex string\n"
  
              "\nResult:\n"
              "{\n"
              "  \"txid\" : \"id\",        (string) The transaction id\n"
              "  \"size\" : n,             (numeric) The transaction size\n"
              "  \"version\" : n,          (numeric) The version\n"
              "  \"locktime\" : ttt,       (numeric) The lock time\n"
              "  \"vin\" : [               (array of json objects)\n"
              "     {\n"
              "       \"txid\": \"id\",    (string) The transaction id\n"
              "       \"vout\": n,         (numeric) The output number\n"
              "       \"scriptSig\": {     (json object) The script\n"
              "         \"asm\": \"asm\",  (string) asm\n"
              "         \"hex\": \"hex\"   (string) hex\n"
              "       },\n"
              "       \"sequence\": n     (numeric) The script sequence number\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "  \"vout\" : [             (array of json objects)\n"
              "     {\n"
              "       \"value\" : x.xxx,            (numeric) The value in btc\n"
              "       \"n\" : n,                    (numeric) index\n"
              "       \"scriptPubKey\" : {          (json object)\n"
              "         \"asm\" : \"asm\",          (string) the asm\n"
              "         \"hex\" : \"hex\",          (string) the hex\n"
              "         \"reqSigs\" : n,            (numeric) The required sigs\n"
              "         \"type\" : \"pubkeyhash\",  (string) The type, eg 'pubkeyhash'\n"
              "         \"addresses\" : [           (json array of string)\n"
              "           \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\"   (string) hodlcash address\n"
              "           ,...\n"
              "         ]\n"
              "       }\n"
              "     }\n"
              "     ,...\n"
              "  ],\n"
              "}\n"
  
              "\nExamples:\n" +
              HelpExampleCli("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\""));
  
      LOCK(cs_main);
      RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
  
      CTransaction tx;
  
      if (!DecodeHexTx(tx, params[0].get_str()))
          throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
  
      UniValue result(UniValue::VOBJ);
      TxToJSON(tx, 0, result);
  
      return result;
  }
  
  UniValue decodescript(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() != 1)
          throw std::runtime_error(
              "decodescript \"hex\"\n"
              "\nDecode a hex-encoded script.\n"
  
              "\nArguments:\n"
              "1. \"hex\"     (string) the hex encoded script\n"
  
              "\nResult:\n"
              "{\n"
              "  \"asm\":\"asm\",   (string) Script public key\n"
              "  \"hex\":\"hex\",   (string) hex encoded public key\n"
              "  \"type\":\"type\", (string) The output type\n"
              "  \"reqSigs\": n,    (numeric) The required signatures\n"
              "  \"addresses\": [   (json array of string)\n"
              "     \"address\"     (string) hodlcash address\n"
              "     ,...\n"
              "  ],\n"
              "  \"p2sh\",\"address\" (string) script address\n"
              "}\n"
  
              "\nExamples:\n" +
              HelpExampleCli("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\""));
  
      LOCK(cs_main);
      RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
  
      UniValue r(UniValue::VOBJ);
      CScript script;
      if (params[0].get_str().size() > 0) {
          std::vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
          script = CScript(scriptData.begin(), scriptData.end());
      } else {
          // Empty scripts are valid
      }
      ScriptPubKeyToJSON(script, r, false);
  
      r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
      return r;
  }
  
  /** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
  static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
  {
      UniValue entry(UniValue::VOBJ);
      entry.push_back(Pair("txid", txin.prevout.hash.ToString()));
      entry.push_back(Pair("vout", (uint64_t)txin.prevout.n));
      entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
      entry.push_back(Pair("sequence", (uint64_t)txin.nSequence));
      entry.push_back(Pair("error", strMessage));
      vErrorsRet.push_back(entry);
  }
  
  UniValue signrawtransaction(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() < 1 || params.size() > 4)
          throw std::runtime_error(
              "signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
              "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
              "The second optional argument (may be null) is an array of previous transaction outputs that\n"
              "this transaction depends on but may not yet be in the block chain.\n"
              "The third optional argument (may be null) is an array of base58-encoded private\n"
              "keys that, if given, will be the only keys used to sign the transaction.\n"
  #ifdef ENABLE_WALLET
              + HelpRequiringPassphrase() + "\n"
  #endif
  
              "\nArguments:\n"
              "1. \"hexstring\"     (string, required) The transaction hex string\n"
              "2. \"prevtxs\"       (string, optional) An json array of previous dependent transaction outputs\n"
              "     [               (json array of json objects, or 'null' if none provided)\n"
              "       {\n"
              "         \"txid\":\"id\",             (string, required) The transaction id\n"
              "         \"vout\":n,                  (numeric, required) The output number\n"
              "         \"scriptPubKey\": \"hex\",   (string, required) script key\n"
              "         \"redeemScript\": \"hex\"    (string, required for P2SH) redeem script\n"
              "       }\n"
              "       ,...\n"
              "    ]\n"
              "3. \"privatekeys\"     (string, optional) A json array of base58-encoded private keys for signing\n"
              "    [                  (json array of strings, or 'null' if none provided)\n"
              "      \"privatekey\"   (string) private key in base58-encoding\n"
              "      ,...\n"
              "    ]\n"
              "4. \"sighashtype\"     (string, optional, default=ALL) The signature hash type. Must be one of\n"
              "       \"ALL\"\n"
              "       \"NONE\"\n"
              "       \"SINGLE\"\n"
              "       \"ALL|ANYONECANPAY\"\n"
              "       \"NONE|ANYONECANPAY\"\n"
              "       \"SINGLE|ANYONECANPAY\"\n"
  
              "\nResult:\n"
              "{\n"
              "  \"hex\" : \"value\",           (string) The hex-encoded raw transaction with signature(s)\n"
              "  \"complete\" : true|false,   (boolean) If the transaction has a complete set of signatures\n"
              "  \"errors\" : [                 (json array of objects) Script verification errors (if there are any)\n"
              "    {\n"
              "      \"txid\" : \"hash\",           (string) The hash of the referenced, previous transaction\n"
              "      \"vout\" : n,                (numeric) The index of the output to spent and used as input\n"
              "      \"scriptSig\" : \"hex\",       (string) The hex-encoded signature script\n"
              "      \"sequence\" : n,            (numeric) Script sequence number\n"
              "      \"error\" : \"text\"           (string) Verification or signing error related to the input\n"
              "    }\n"
              "    ,...\n"
              "  ]\n"
              "}\n"
  
              "\nExamples:\n" +
              HelpExampleCli("signrawtransaction", "\"myhex\"") + HelpExampleRpc("signrawtransaction", "\"myhex\""));
  
  #ifdef ENABLE_WALLET
      LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
  #else
      LOCK(cs_main);
  #endif
      RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
  
      std::vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
      CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
      std::vector<CMutableTransaction> txVariants;
      while (!ssData.empty()) {
          try {
              CMutableTransaction tx;
              ssData >> tx;
              txVariants.push_back(tx);
          } catch (const std::exception&) {
              throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
          }
      }
  
      if (txVariants.empty())
          throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
  
      // mergedTx will end up with all the signatures; it
      // starts as a clone of the rawtx:
      CMutableTransaction mergedTx(txVariants[0]);
  
      // Fetch previous transactions (inputs):
      std::map<COutPoint, CScript> mapPrevOut;
      if (Params().NetworkID() == CBaseChainParams::REGTEST) {
          for (const CTxIn &txbase : mergedTx.vin)
          {
              CTransaction tempTx;
              uint256 hashBlock;
              if (GetTransaction(txbase.prevout.hash, tempTx, hashBlock, true)) {
                  // Copy results into mapPrevOut:
                  mapPrevOut[txbase.prevout] = tempTx.vout[txbase.prevout.n].scriptPubKey;
              }
          }
      }
      CCoinsView viewDummy;
      CCoinsViewCache view(&viewDummy);
      {
          LOCK(mempool.cs);
          CCoinsViewCache& viewChain = *pcoinsTip;
          CCoinsViewMemPool viewMempool(&viewChain, mempool);
          view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
  
          for (const CTxIn& txin : mergedTx.vin) {
              const uint256& prevHash = txin.prevout.hash;
              CCoins coins;
              view.AccessCoins(prevHash); // this is certainly allowed to fail
          }
  
          view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
      }
  
      bool fGivenKeys = false;
      CBasicKeyStore tempKeystore;
      if (params.size() > 2 && !params[2].isNull()) {
          fGivenKeys = true;
          UniValue keys = params[2].get_array();
          for (unsigned int idx = 0; idx < keys.size(); idx++) {
              UniValue k = keys[idx];
              CBitcoinSecret vchSecret;
              bool fGood = vchSecret.SetString(k.get_str());
              if (!fGood)
                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
              CKey key = vchSecret.GetKey();
              if (!key.IsValid())
                  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
              tempKeystore.AddKey(key);
          }
      }
  #ifdef ENABLE_WALLET
      else if (pwalletMain)
          EnsureWalletIsUnlocked();
  #endif
  
      // Add previous txouts given in the RPC call:
      if (params.size() > 1 && !params[1].isNull()) {
          UniValue prevTxs = params[1].get_array();
          for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
              const UniValue& p = prevTxs[idx];
              if (!p.isObject())
                  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
  
              UniValue prevOut = p.get_obj();
  
              RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR));
  
              uint256 txid = ParseHashO(prevOut, "txid");
  
              int nOut = find_value(prevOut, "vout").get_int();
              if (nOut < 0)
                  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
  
              std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
              CScript scriptPubKey(pkData.begin(), pkData.end());
  
              {
                  CCoinsModifier coins = view.ModifyCoins(txid);
                  if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
                      std::string err("Previous output scriptPubKey mismatch:\n");
                      err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n" +
                            scriptPubKey.ToString();
                      throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
                  }
                  if ((unsigned int)nOut >= coins->vout.size())
                      coins->vout.resize(nOut + 1);
                  coins->vout[nOut].scriptPubKey = scriptPubKey;
                  coins->vout[nOut].nValue = 0; // we don't know the actual output value
              }
  
              // if redeemScript given and not using the local wallet (private keys
              // given), add redeemScript to the tempKeystore so it can be signed:
              if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) {
                  RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR));
                  UniValue v = find_value(prevOut, "redeemScript");
                  if (!v.isNull()) {
                      std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
                      CScript redeemScript(rsData.begin(), rsData.end());
                      tempKeystore.AddCScript(redeemScript);
                  }
              }
          }
      }
  
  #ifdef ENABLE_WALLET
      const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
  #else
      const CKeyStore& keystore = tempKeystore;
  #endif
  
      int nHashType = SIGHASH_ALL;
      if (params.size() > 3 && !params[3].isNull()) {
          static std::map<std::string, int> mapSigHashValues =
              boost::assign::map_list_of(std::string("ALL"), int(SIGHASH_ALL))(std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))(std::string("NONE"), int(SIGHASH_NONE))(std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE | SIGHASH_ANYONECANPAY))(std::string("SINGLE"), int(SIGHASH_SINGLE))(std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY));
          std::string strHashType = params[3].get_str();
          if (mapSigHashValues.count(strHashType))
              nHashType = mapSigHashValues[strHashType];
          else
              throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
      }
  
      bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
  
      // Script verification errors
      UniValue vErrors(UniValue::VARR);
  
      // Sign what we can:
      for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
          CTxIn& txin = mergedTx.vin[i];
          const CCoins* coins = view.AccessCoins(txin.prevout.hash);
          if (Params().NetworkID() == CBaseChainParams::REGTEST) {
              if (mapPrevOut.count(txin.prevout) == 0 && (coins == NULL || !coins->IsAvailable(txin.prevout.n)))
              {
                  TxInErrorToJSON(txin, vErrors, "Input not found");
                  continue;
              }
          } else {
              if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
                  TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
                  continue;
              }
          }
          const CScript& prevPubKey = (Params().NetworkID() == CBaseChainParams::REGTEST && mapPrevOut.count(txin.prevout) != 0 ? mapPrevOut[txin.prevout] : coins->vout[txin.prevout.n].scriptPubKey);
  
          txin.scriptSig.clear();
  
          // if this is a P2CS script, select which key to use
          bool fColdStake = false;
          if (prevPubKey.IsPayToColdStaking()) {
              // if we have both keys, sign with the spender key
              fColdStake = !bool(IsMine(keystore, prevPubKey) & ISMINE_SPENDABLE_DELEGATED);
          }
  
          // Only sign SIGHASH_SINGLE if there's a corresponding output:
          if (!fHashSingle || (i < mergedTx.vout.size()))
              SignSignature(keystore, prevPubKey, mergedTx, i, nHashType, fColdStake);
  
          // ... and merge in other signatures:
          for (const CMutableTransaction& txv : txVariants) {
              txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
          }
          ScriptError serror = SCRIPT_ERR_OK;
          if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) {
              TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
          }
      }
      bool fComplete = vErrors.empty();
  
      UniValue result(UniValue::VOBJ);
      result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
      result.push_back(Pair("complete", fComplete));
      if (!vErrors.empty()) {
          result.push_back(Pair("errors", vErrors));
      }
  
      return result;
  }
  
  UniValue sendrawtransaction(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() < 1 || params.size() > 3)
          throw std::runtime_error(
              "sendrawtransaction \"hexstring\" ( allowhighfees )\n"
              "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
              "\nAlso see createrawtransaction and signrawtransaction calls.\n"
  
              "\nArguments:\n"
              "1. \"hexstring\"    (string, required) The hex string of the raw transaction)\n"
              "2. allowhighfees    (boolean, optional, default=false) Allow high fees\n"
              "3. swiftx           (boolean, optional, default=false) Use SwiftX to send this transaction\n"
  
              "\nResult:\n"
              "\"hex\"             (string) The transaction hash in hex\n"
  
              "\nExamples:\n"
              "\nCreate a transaction\n" +
              HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
              "Sign the transaction, and get back the hex\n" + HelpExampleCli("signrawtransaction", "\"myhex\"") +
              "\nSend the transaction (signed hex)\n" + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
              "\nAs a json rpc call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\""));
  
      LOCK(cs_main);
      RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
  
      // parse hex string from parameter
      CTransaction tx;
      if (!DecodeHexTx(tx, params[0].get_str()))
          throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
      uint256 hashTx = tx.GetHash();
  
      bool fOverrideFees = false;
      if (params.size() > 1)
          fOverrideFees = params[1].get_bool();
  
      bool fSwiftX = false;
      if (params.size() > 2)
          fSwiftX = params[2].get_bool();
  
      CCoinsViewCache& view = *pcoinsTip;
      const CCoins* existingCoins = view.AccessCoins(hashTx);
      bool fHaveMempool = mempool.exists(hashTx);
      bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
      if (!fHaveMempool && !fHaveChain) {
          // push to local node and sync with wallets
          if (fSwiftX) {
              mapTxLockReq.insert(std::make_pair(tx.GetHash(), tx));
              CreateNewLock(tx);
              RelayTransactionLockReq(tx, true);
          }
          CValidationState state;
          bool fMissingInputs;
          if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) {
              if (state.IsInvalid()) {
                  throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
              } else {
                  if (fMissingInputs) {
                      throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
                  }
                  throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());
              }
          }
      } else if (fHaveChain) {
          throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
      }
      RelayTransaction(tx);
  
      return hashTx.GetHex();
  }
  
  UniValue getspentzerocoinamount(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() != 2)
          throw std::runtime_error(
              "getspentzerocoinamount hexstring index\n"
              "\nReturns value of spent zerocoin output designated by transaction hash and input index.\n"
  
              "\nArguments:\n"
              "1. hash          (hexstring) Transaction hash\n"
              "2. index         (int) Input index\n"
  
              "\nResult:\n"
              "\"value\"        (int) Spent output value, -1 if error\n"
  
              "\nExamples:\n" +
              HelpExampleCli("getspentzerocoinamount", "78021ebf92a80dfccef1413067f1222e37535399797cce029bb40ad981131706 0"));
  
      LOCK(cs_main);
  
      uint256 txHash = ParseHashV(params[0], "parameter 1");
      int inputIndex = params[1].get_int();
      if (inputIndex < 0)
          throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter for transaction input");
  
      CTransaction tx;
      uint256 hashBlock = 0;
      if (!GetTransaction(txHash, tx, hashBlock, true))
          throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
  
      if (inputIndex >= (int)tx.vin.size())
          throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter for transaction input");
  
      const CTxIn& input = tx.vin[inputIndex];
      if (!input.IsZerocoinSpend())
          return -1;
  
      libzerocoin::CoinSpend spend = TxInToZerocoinSpend(input);
      CAmount nValue = libzerocoin::ZerocoinDenominationToAmount(spend.getDenomination());
      return FormatMoney(nValue);
  }
  
  #ifdef ENABLE_WALLET
  UniValue createrawzerocoinstake(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() != 1)
          throw std::runtime_error(
              "createrawzerocoinstake mint_input \n"
              "\nCreates raw zHODL coinstakes (without MN output). Only for regtest\n" +
              HelpRequiringPassphrase() + "\n"
  
              "\nArguments:\n"
              "1. mint_input      (hex string, required) serial hash of the mint used as input\n"
  
              "\nResult:\n"
              "{\n"
              "   \"hex\": \"xxx\",           (hex string) raw coinstake transaction\n"
              "   \"private-key\": \"xxx\"    (hex string) private key of the input mint [needed to\n"
              "                                            sign a block with this stake]"
              "}\n"
              "\nExamples\n" +
              HelpExampleCli("createrawzerocoinstake", "0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f") +
              HelpExampleRpc("createrawzerocoinstake", "0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f"));
  
  
      if (Params().NetworkID() != CBaseChainParams::REGTEST)
          throw JSONRPCError(RPC_WALLET_ERROR, "createrawzerocoinstake is available only on regtest net");
  
      assert(pwalletMain != NULL);
      LOCK2(cs_main, pwalletMain->cs_wallet);
  
      if(sporkManager.IsSporkActive(SPORK_16_ZEROCOIN_MAINTENANCE_MODE))
          throw JSONRPCError(RPC_WALLET_ERROR, "zHODL is currently disabled due to maintenance.");
  
      std::string serial_hash = params[0].get_str();
      if (!IsHex(serial_hash))
          throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex serial hash");
  
      EnsureWalletIsUnlocked();
  
      uint256 hashSerial(serial_hash);
      CZerocoinMint input_mint;
      if (!pwalletMain->GetMint(hashSerial, input_mint)) {
          std::string strErr = "Failed to fetch mint associated with serial hash " + serial_hash;
          throw JSONRPCError(RPC_WALLET_ERROR, strErr);
      }
  
      CMutableTransaction coinstake_tx;
  
      // create the zerocoinmint output (one spent denom + three 1-zHODL denom)
      libzerocoin::CoinDenomination staked_denom = input_mint.GetDenomination();
      std::vector<CTxOut> vOutMint(5);
      // Mark coin stake transaction
      CScript scriptEmpty;
      scriptEmpty.clear();
      vOutMint[0] = CTxOut(0, scriptEmpty);
      CDeterministicMint dMint;
      if (!pwalletMain->CreateZHODLOutPut(staked_denom, vOutMint[1], dMint))
          throw JSONRPCError(RPC_WALLET_ERROR, "failed to create new zpiv output");
  
      for (int i=2; i<5; i++) {
          if (!pwalletMain->CreateZHODLOutPut(libzerocoin::ZQ_ONE, vOutMint[i], dMint))
              throw JSONRPCError(RPC_WALLET_ERROR, "failed to create new zpiv output");
      }
      coinstake_tx.vout = vOutMint;
  
      //hash with only the output info in it to be used in Signature of Knowledge
      uint256 hashTxOut = coinstake_tx.GetHash();
      CZerocoinSpendReceipt receipt;
  
      // create the zerocoinspend input
      CTxIn newTxIn;
      // Use v2 spends for input (with v3 zpiv staking is disabled)
      if (!pwalletMain->MintToTxIn(input_mint, hashTxOut, newTxIn, receipt, libzerocoin::SpendType::STAKE, nullptr, false))
          throw JSONRPCError(RPC_WALLET_ERROR, "failed to create zc-spend stake input");
  
      coinstake_tx.vin.push_back(newTxIn);
  
      UniValue ret(UniValue::VOBJ);
      ret.push_back(Pair("hex", EncodeHexTx(coinstake_tx)));
      CPrivKey pk = input_mint.GetPrivKey();
      CKey key;
      key.SetPrivKey(pk, true);
      ret.push_back(Pair("private-key", HexStr(key)));
      return ret;
  
  }
  
  UniValue createrawzerocoinspend(const UniValue& params, bool fHelp)
  {
      if (fHelp || params.size() < 1 || params.size() > 3)
          throw std::runtime_error(
              "createrawzerocoinspend mint_input ( \"address\" isPublicSpend )\n"
              "\nCreates raw zHODL public spend.\n" +
              HelpRequiringPassphrase() + "\n"
  
              "\nArguments:\n"
              "1. mint_input      (hex string, required) serial hash of the mint used as input\n"
              "2. \"address\"     (string, optional, default=change) Send to specified address or to a new change address.\n"
              "3. isPublicSpend   (boolean, optional, default=true) create a public zc spend."
              "                       If false, instead create spend version 2 (only for regression tests)"
  
  
              "\nResult:\n"
              "{\n"
              "   \"hex\": \"xxx\",           (hex string) raw public spend signed transaction\n"
              "}\n"
              "\nExamples\n" +
              HelpExampleCli("createrawzerocoinspend", "0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f") +
              HelpExampleRpc("createrawzerocoinspend", "0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f"));
  
      const std::string serial_hash = params[0].get_str();
      const std::string address_str = (params.size() > 1 ? params[1].get_str() : "");
      const bool isPublicSpend = (params.size() > 2 ? params[2].get_bool() : true);
  
      if (!IsHex(serial_hash))
          throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex serial hash");
  
      CBitcoinAddress address;
      CBitcoinAddress* addr_ptr = nullptr;
      if (address_str != "") {
          address = CBitcoinAddress(address_str);
          if(!address.IsValid())
              throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid HodlCash address");
          addr_ptr = &address;
      }
  
      if (Params().NetworkID() != CBaseChainParams::REGTEST && !isPublicSpend)
          throw JSONRPCError(RPC_WALLET_ERROR, "zHODL old spend only available in regtest for tests purposes");
  
      assert(pwalletMain != NULL);
      EnsureWalletIsUnlocked();
      LOCK2(cs_main, pwalletMain->cs_wallet);
  
      uint256 hashSerial(serial_hash);
      CZerocoinMint input_mint;
      if (!pwalletMain->GetMint(hashSerial, input_mint)) {
          std::string strErr = "Failed to fetch mint associated with serial hash " + serial_hash;
          throw JSONRPCError(RPC_WALLET_ERROR, strErr);
      }
      CAmount nAmount = input_mint.GetDenominationAsAmount();
      std::vector<CZerocoinMint> vMintsSelected = std::vector<CZerocoinMint>(1,input_mint);
  
      // create the spend
      CWalletTx rawTx;
      CZerocoinSpendReceipt receipt;
      CReserveKey reserveKey(pwalletMain);
      std::vector<CDeterministicMint> vNewMints;
      std::list<std::pair<CBitcoinAddress*, CAmount>> outputs;
      if (addr_ptr) {
          outputs.push_back(std::pair<CBitcoinAddress*, CAmount>(addr_ptr, nAmount));
      }
      if (!pwalletMain->CreateZerocoinSpendTransaction(nAmount, rawTx, reserveKey, receipt, vMintsSelected, vNewMints, false, true, outputs, nullptr, isPublicSpend))
          throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage());
  
      // output the raw transaction
      return EncodeHexTx(rawTx);
  }
  #endif
  
  