LCOV - code coverage report
Current view: top level - src/wallet - rpcwallet.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 1805 2330 77.5 %
Date: 2026-08-09 10:51:41 Functions: 84 86 97.7 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin developers
       3             : // Copyright (c) 2014-2015 The Dash developers
       4             : // Copyright (c) 2015-2022 The PIVX Core developers
       5             : // Distributed under the MIT software license, see the accompanying
       6             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       7             : 
       8             : #include "wallet/rpcwallet.h"
       9             : 
      10             : #include "addressbook.h"
      11             : #include "amount.h"
      12             : #include "coincontrol.h"
      13             : #include "core_io.h"
      14             : #include "destination_io.h"
      15             : #include "httpserver.h"
      16             : #include "key_io.h"
      17             : #include "masternode-sync.h"
      18             : #include "messagesigner.h"
      19             : #include "net.h"
      20             : #include "policy/feerate.h"
      21             : #include "primitives/transaction.h"
      22             : #include "rpc/server.h"
      23             : #include "sapling/key_io_sapling.h"
      24             : #include "sapling/sapling_operation.h"
      25             : #include "shutdown.h"
      26             : #include "spork.h"
      27             : #include "timedata.h"
      28             : #include "utilmoneystr.h"
      29             : #include "wallet/wallet.h"
      30             : #include "wallet/walletdb.h"
      31             : #include "wallet/walletutil.h"
      32             : 
      33             : #include <stdint.h>
      34             : #include <univalue.h>
      35             : 
      36             : 
      37             : static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
      38             : 
      39        9060 : CWallet* GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
      40             : {
      41        9060 :     if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
      42             :         // wallet endpoint was used
      43          55 :         std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
      44          93 :         for (CWalletRef pwallet : ::vpwallets) {
      45          92 :             if (pwallet->GetName() == requestedWallet) {
      46          27 :                 return pwallet;
      47             :             }
      48             :         }
      49           2 :         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
      50             :     }
      51        9032 :     return ::vpwallets.size() == 1 || (request.fHelp && ::vpwallets.size() > 0) ? ::vpwallets[0] : nullptr;
      52             : }
      53             : 
      54           8 : std::string HelpRequiringPassphrase(CWallet* const pwallet)
      55             : {
      56          15 :     return pwallet && pwallet->IsCrypted() ? "\nRequires wallet passphrase to be set with walletpassphrase call." : "";
      57             : }
      58             : 
      59        7702 : bool EnsureWalletIsAvailable(CWallet* const pwallet, bool avoidException)
      60             : {
      61        7702 :     if (pwallet) return true;
      62           2 :     if (avoidException) return false;
      63           2 :     if (::vpwallets.empty()) {
      64             :         // Wallet RPC methods are disabled if no wallets are loaded.
      65           0 :         throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
      66             :     }
      67           2 :     throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
      68           4 :         "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
      69             : }
      70             : 
      71        3450 : void EnsureWalletIsUnlocked(CWallet* const pwallet, bool fAllowAnonOnly)
      72             : {
      73        3450 :     if (pwallet->IsLocked() || (!fAllowAnonOnly && pwallet->fWalletUnlockStaking))
      74          10 :         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
      75        3445 : }
      76             : 
      77         377 : static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
      78             : {
      79         377 :     AssertLockHeld(cs_main);
      80             : 
      81         377 :     int confirms = wtx.GetDepthInMainChain();
      82         377 :     entry.pushKV("confirmations", confirms);
      83         377 :     entry.pushKV("bcconfirmations", confirms);      // DEPRECATED in 4.3.99
      84         544 :     if (wtx.IsCoinBase() || wtx.IsCoinStake())
      85         420 :         entry.pushKV("generated", true);
      86         377 :     if (confirms > 0) {
      87         606 :         entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
      88         303 :         entry.pushKV("blockindex", wtx.m_confirm.nIndex);
      89         303 :         entry.pushKV("blocktime", LookupBlockIndex(wtx.m_confirm.hashBlock)->GetBlockTime());
      90             :     } else {
      91         148 :         entry.pushKV("trusted", wtx.IsTrusted());
      92             :     }
      93         377 :     uint256 hash = wtx.GetHash();
      94         754 :     entry.pushKV("txid", hash.GetHex());
      95         754 :     UniValue conflicts(UniValue::VARR);
      96         386 :     for (const uint256& conflict : wtx.GetConflicts())
      97          18 :         conflicts.push_back(conflict.GetHex());
      98         377 :     entry.pushKV("walletconflicts", conflicts);
      99         377 :     entry.pushKV("time", wtx.GetTxTime());
     100         377 :     entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
     101         378 :     for (const std::pair<std::string, std::string> & item : wtx.mapValue)
     102           1 :         entry.pushKV(item.first, item.second);
     103         377 : }
     104             : 
     105         216 : std::string LabelFromValue(const UniValue& value)
     106             : {
     107         216 :     std::string label = value.get_str();
     108         216 :     if (label == "*")
     109           0 :         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
     110         216 :     return label;
     111             : }
     112             : 
     113        1115 : static CTxDestination GetNewAddressFromLabel(CWallet* const pwallet, const std::string purpose, const UniValue &params,
     114             :                                              const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS)
     115             : {
     116        2230 :     LOCK2(cs_main, pwallet->cs_wallet);
     117             :     // Parse the label first so we don't generate a key if there's an error
     118        2230 :     std::string label;
     119        1115 :     if (!params.isNull() && params.size() > 0)
     120         118 :         label = LabelFromValue(params[0]);
     121             : 
     122        3348 :     auto r = pwallet->getNewAddress(label, purpose, addrType);
     123        1115 :     if(!r)
     124           6 :         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, r.getError());
     125        2224 :     return *r.getObjResult();
     126             : }
     127             : 
     128             : /** Convert CAddressBookData to JSON record.  */
     129         613 : static UniValue AddressBookDataToJSON(const AddressBook::CAddressBookData& data, const bool verbose)
     130             : {
     131         613 :     UniValue ret(UniValue::VOBJ);
     132         613 :     if (verbose) {
     133         854 :         ret.pushKV("name", data.name);
     134             :     }
     135         613 :     ret.pushKV("purpose", data.purpose);
     136         613 :     return ret;
     137             : }
     138             : 
     139             : /** Checks if a CKey is in the given CWallet compressed or otherwise*/
     140           4 : bool HaveKey(const CWallet* wallet, const CKey& key)
     141             : {
     142           4 :     CKey key2;
     143           8 :     key2.Set(key.begin(), key.end(), !key.IsCompressed());
     144           8 :     return wallet->HaveKey(key.GetPubKey().GetID()) || wallet->HaveKey(key2.GetPubKey().GetID());
     145             : }
     146             : 
     147         550 : UniValue getaddressinfo(const JSONRPCRequest& request)
     148             : {
     149         550 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     150             : 
     151         550 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     152           0 :         return NullUniValue;
     153             : 
     154        1100 :     const std::string example_address = "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\"";
     155             : 
     156         550 :     if (request.fHelp || request.params.size() > 1)
     157           0 :         throw std::runtime_error(
     158             :                 "getaddressinfo ( \"address\" )\n"
     159             :                 "\nReturn information about the given PIVX address.\n"
     160             :                 "Some of the information will only be present if the address is in the active wallet.\n"
     161             :                 "Metadata for shield addresses is available only if the wallet is unlocked.\n"
     162             :                 "{Result:\n"
     163             :                 "  \"address\" : \"address\",              (string) The PIVX address validated.\n"
     164             :                 "  \"isshield\" : true|false,            (boolean) If the address is shield or transparent.\n"
     165             :                 "  \"scriptPubKey\" : \"hex\",             (string, only if isshield=false) The hex-encoded scriptPubKey generated by the address.\n"
     166             :                 "  \"ischange\" : true|false,            (boolean) If the transparent address was used for change output.\n"
     167             :                 "  \"ismine\" : true|false,              (boolean) If the address is yours.\n"
     168             :                 "  \"iswatchonly\" : true|false,         (boolean) If the address is watchonly.\n"
     169             :                 "  \"label\" :  \"label\"                  (string) The label associated with the address, \"\" is the default label.\n"
     170             :                 "  \"timestamp\" : timestamp,            (number, optional) The creation time of the key, if available, expressed in the UNIX epoch time.\n"
     171             :                 "  \"hdkeypath\" : \"keypath\"             (string, optional) The HD keypath, if the key is HD and available.\n"
     172             :                 "  \"hdseedid\" : \"<hash160>\"            (string, optional) The Hash160 of the HD seed.\n"
     173             :                 "  \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) The fingerprint of the master key.\n"
     174             :                 "  \"labels\"                            (json object) An array of labels associated with the address. Currently limited to one label but returned\n"
     175             :                 "                                               as an array to keep the API stable if multiple labels are enabled in the future.\n"
     176             :                 "    [\n"
     177             :                 "      { (json object of label data)\n"
     178             :                 "        \"name\" : \"labelname\" (string) The label.\n"
     179             :                 "        \"purpose\" : \"purpose\" (string) The purpose of the associated address (send or receive).\n"
     180             :                 "      }\n"
     181             :                 "    ]\n"
     182             :                 "}\n"
     183             : 
     184           0 :                 "\nExamples:\n" +
     185           0 :                 HelpExampleCli("getaddressinfo", example_address) + HelpExampleRpc("getaddressinfo", example_address)
     186           0 :                 );
     187             : 
     188        1100 :     LOCK(pwallet->cs_wallet);
     189             : 
     190         550 :     const std::string& strAdd = request.params[0].get_str();
     191        1100 :     UniValue ret(UniValue::VOBJ);
     192         550 :     ret.pushKV("address", strAdd);
     193             : 
     194        1100 :     const CWDestination& dest = Standard::DecodeDestination(strAdd);
     195             :     // Make sure the destination is valid
     196         550 :     if (!Standard::IsValidDestination(dest)) {
     197           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
     198             :     }
     199             : 
     200         550 :     const CTxDestination* pTransDest = Standard::GetTransparentDestination(dest);
     201         550 :     ret.pushKV("isshield", pTransDest == nullptr);
     202             : 
     203         550 :     if (pTransDest) {
     204         984 :         CScript scriptPubKey = GetScriptForDestination(*pTransDest);
     205        1476 :         ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
     206         984 :         ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
     207             :     }
     208             : 
     209         550 :     isminetype mine = IsMine(*pwallet, dest);
     210         550 :     ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE_ALL));
     211         550 :     ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY_ALL));
     212             : 
     213             :     // Return label field if existing. Currently only one label can be
     214             :     // associated with an address, so the label should be equivalent to the
     215             :     // value of the name key/value pair in the labels array below.
     216         550 :     if (pwallet->HasAddressBook(dest)) {
     217         854 :         ret.pushKV("label", pwallet->GetNameForAddressBookEntry(dest));
     218             :     }
     219             : 
     220         550 :     ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan();
     221         550 :     SaplingScriptPubKeyMan* sspk_man = pwallet->GetSaplingScriptPubKeyMan();
     222         550 :     CKeyMetadata* meta = nullptr;
     223             : 
     224         550 :     if (spk_man && pTransDest) {
     225             :         // transparent destination
     226         492 :         const CKeyID* keyID = boost::get<CKeyID>(pTransDest);
     227         492 :         if (keyID) {
     228         474 :             auto it = pwallet->mapKeyMetadata.find(*keyID);
     229         474 :             if(it != pwallet->mapKeyMetadata.end()) {
     230         474 :                 meta = &it->second;
     231             :             }
     232             :         }
     233          58 :     } else if (sspk_man && !pTransDest) {
     234             :         // shield destination
     235          58 :         const libzcash::SaplingPaymentAddress pa = *Standard::GetShieldedDestination(dest);
     236          58 :         libzcash::SaplingExtendedSpendingKey extsk;
     237          58 :         if (pwallet->GetSaplingExtendedSpendingKey(pa, extsk)) {
     238          58 :             const auto& ivk = extsk.expsk.full_viewing_key().in_viewing_key();
     239          58 :             auto it = sspk_man->mapSaplingZKeyMetadata.find(ivk);
     240          58 :             if (it != sspk_man->mapSaplingZKeyMetadata.end()) {
     241          58 :                 meta = &it->second;
     242             :             }
     243             :         }
     244             :     }
     245             : 
     246             :     // Add metadata
     247         532 :     if (meta) {
     248         532 :         ret.pushKV("timestamp", meta->nCreateTime);
     249         532 :         if (meta->HasKeyOrigin()) {
     250         740 :             ret.pushKV("hdkeypath", meta->key_origin.pathToString());
     251         740 :             ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
     252         740 :             ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint));
     253             :         }
     254             :     }
     255             : 
     256             :     // Return a `labels` array containing the label associated with the address,
     257             :     // equivalent to the `label` field above. Currently only one label can be
     258             :     // associated with an address, but we return an array so the API remains
     259             :     // stable if we allow multiple labels to be associated with an address in
     260             :     // the future.
     261             :     //
     262             :     // DEPRECATED: The previous behavior of returning an array containing a JSON
     263             :     // object of `name` and `purpose` key/value pairs has been deprecated.
     264        1100 :     UniValue labels(UniValue::VARR);
     265        1100 :     auto addrBookData = pwallet->GetAddressBookEntry(dest);
     266         550 :     if (addrBookData) {
     267         427 :         labels.push_back(AddressBookDataToJSON(*addrBookData, true));
     268             :     }
     269         550 :     ret.pushKV("labels", std::move(labels));
     270             : 
     271         550 :     return ret;
     272             : }
     273             : 
     274          61 : UniValue getaddressesbylabel(const JSONRPCRequest& request)
     275             : {
     276          61 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     277             : 
     278          61 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     279           0 :         return NullUniValue;
     280             : 
     281          61 :     if (request.fHelp || request.params.size() != 1)
     282           0 :         throw std::runtime_error(
     283             :             "getaddressesbylabel \"label\"\n"
     284             :             "\nReturns the list of addresses assigned the specified label.\n"
     285             : 
     286             :             "\nArguments:\n"
     287             :             "1. \"label\"  (string, required) The label.\n"
     288             : 
     289             :             "\nResult:\n"
     290             :             "{ (json object with addresses as keys)\n"
     291             :             "  \"address\": { (json object with information about address)\n"
     292             :             "    \"purpose\": \"string\" (string)  Purpose of address (\"send\" for sending address, \"receive\" for receiving address)\n"
     293             :             "  },...\n"
     294             :             "}\n"
     295             : 
     296             :             "\nExamples:\n"
     297           0 :             + HelpExampleCli("getaddressesbylabel", "\"tabby\"")
     298           0 :             + HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
     299           0 :         );
     300             : 
     301         107 :     LOCK(pwallet->cs_wallet);
     302             : 
     303         122 :     std::string label = LabelFromValue(request.params[0]);
     304             : 
     305             :     // Find all addresses that have the given label
     306         122 :     UniValue ret(UniValue::VOBJ);
     307        2746 :     for (auto it = pwallet->NewAddressBookIterator(); it.IsValid(); it.Next()) {
     308        2624 :         auto addrBook = it.GetValue();
     309        1312 :         if (addrBook.name == label) {
     310         186 :             if (!addrBook.isShielded()) {
     311         304 :                 ret.pushKV(EncodeDestination(*it.GetCTxDestKey(), AddressBook::IsColdStakingPurpose(addrBook.purpose), AddressBook::IsExchangePurpose(addrBook.purpose)), AddressBookDataToJSON(addrBook, false));
     312             :             } else {
     313          68 :                 ret.pushKV(Standard::EncodeDestination(*it.GetShieldedDestKey()), AddressBookDataToJSON(addrBook, false));
     314             :             }
     315             :         }
     316             :     }
     317             : 
     318          61 :     if (ret.empty()) {
     319          30 :         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));
     320             :     }
     321             : 
     322          46 :     return ret;
     323             : }
     324             : 
     325           1 : UniValue listlabels(const JSONRPCRequest& request)
     326             : {
     327           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     328             : 
     329           1 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     330           0 :         return NullUniValue;
     331             : 
     332           1 :     if (request.fHelp || request.params.size() > 1)
     333           0 :         throw std::runtime_error(
     334             :             "listlabels ( \"purpose\" )\n"
     335             :             "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n"
     336             : 
     337             :             "\nArguments:\n"
     338             :             "1. \"purpose\"    (string, optional) Address purpose to list labels for ('send','receive', 'delegable', 'delegator', 'coldstaking', 'coldstaking_send', 'refund'). An empty string is the same as not providing this argument.\n"
     339             : 
     340             :             "\nResult:\n"
     341             :             "[               (json array of string)\n"
     342             :             "  \"label\",      (string) Label name\n"
     343             :             "  ...\n"
     344             :             "]\n"
     345             : 
     346             :             "\nExamples:\n"
     347             :             "\nList all labels\n"
     348           0 :             + HelpExampleCli("listlabels", "") +
     349             :             "\nList labels that have receiving addresses\n"
     350           0 :             + HelpExampleCli("listlabels", "receive") +
     351             :             "\nList labels that have sending addresses\n"
     352           0 :             + HelpExampleCli("listlabels", "send") +
     353             :             "\nAs json rpc call\n"
     354           0 :             + HelpExampleRpc("listlabels", "receive")
     355           0 :         );
     356             : 
     357           2 :     LOCK(pwallet->cs_wallet);
     358             : 
     359           2 :     std::string purpose;
     360           1 :     if (!request.params[0].isNull()) {
     361           0 :         purpose = request.params[0].get_str();
     362             :     }
     363             : 
     364             :     // Add to a set to sort by label name, then insert into Univalue array
     365           2 :     std::set<std::string> label_set;
     366          12 :     for (auto it = pwallet->NewAddressBookIterator(); it.IsValid(); it.Next()) {
     367           5 :         auto addrBook = it.GetValue();
     368           5 :         if (purpose.empty() || addrBook.purpose == purpose) {
     369          10 :             label_set.insert(addrBook.name);
     370             :         }
     371             :     }
     372             : 
     373           2 :     UniValue ret(UniValue::VARR);
     374           6 :     for (const std::string& name : label_set) {
     375           5 :         ret.push_back(name);
     376             :     }
     377             : 
     378           1 :     return ret;
     379             : }
     380             : 
     381           5 : CPubKey parseWIFKey(std::string strKey, CWallet* pwallet)
     382             : {
     383           5 :     CKey key = KeyIO::DecodeSecret(strKey);
     384           5 :     if (!key.IsValid()) {
     385           2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
     386             :     }
     387             : 
     388           4 :     if (HaveKey(pwallet, key)) {
     389           4 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
     390             :     }
     391           4 :     return pwallet->GetScriptPubKeyMan()->DeriveNewSeed(key);
     392             : }
     393             : 
     394           1 : UniValue upgradewallet(const JSONRPCRequest& request)
     395             : {
     396           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     397             : 
     398           1 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     399           0 :         return NullUniValue;
     400             : 
     401           1 :     if (request.fHelp || request.params.size() != 0)
     402           0 :         throw std::runtime_error("upgradewallet\n"
     403             :                                  "Bump the wallet features to the latest supported version. Non-HD wallets will be upgraded to HD wallet functionality. "
     404             :                                  "Marking all the previous keys as pre-split keys and managing them separately. Once the last key in the pre-split keypool gets marked as used (received balance), the wallet will automatically start using the HD generated keys.\n"
     405             :                                  "The upgraded HD wallet will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
     406             :                                  "Wallets that are already running the latest HD version will be upgraded to Sapling support\n"
     407             :                                  "Enabling the Sapling key manager. Sapling keys will be deterministically derived by the same HD wallet seed.\n"
     408             :                                  "Wallets that are running the latest Sapling version will not be upgraded"
     409             :                                  "\nNote that you will need to MAKE A NEW BACKUP of your wallet after upgrade it.\n"
     410           0 :                                  + HelpRequiringPassphrase(pwallet) + "\n"
     411           0 :                                  + HelpExampleCli("upgradewallet", "") + HelpExampleRpc("upgradewallet", "")
     412           0 :         );
     413             : 
     414           3 :     LOCK2(cs_main, pwallet->cs_wallet);
     415             : 
     416             :     // Do not do anything to wallets already upgraded
     417           1 :     if (pwallet->CanSupportFeature(FEATURE_LATEST)) {
     418           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot upgrade the wallet. The wallet is already running the latest version");
     419             :     }
     420             : 
     421           1 :     EnsureWalletIsUnlocked(pwallet);
     422             : 
     423             :     // Get version
     424           1 :     int prev_version = pwallet->GetVersion();
     425             :     // Upgrade wallet's version
     426           1 :     pwallet->SetMinVersion(FEATURE_LATEST);
     427           1 :     pwallet->SetMaxVersion(FEATURE_LATEST);
     428             : 
     429             :     // Upgrade to HD
     430           2 :     std::string upgradeError;
     431           1 :     if (!pwallet->Upgrade(upgradeError, prev_version)) {
     432           0 :         upgradeError = strprintf("Error: Cannot upgrade wallet, %s", upgradeError);
     433           0 :         throw JSONRPCError(RPC_WALLET_ERROR, upgradeError);
     434             :     }
     435             : 
     436           1 :     return NullUniValue;
     437             : }
     438             : 
     439           9 : UniValue sethdseed(const JSONRPCRequest& request)
     440             : {
     441           9 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     442             : 
     443           9 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     444           0 :         return NullUniValue;
     445             : 
     446           9 :     if (request.fHelp || request.params.size() > 2)
     447           1 :         throw std::runtime_error("sethdseed ( newkeypool \"seed\" )\n"
     448             :                "Set or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
     449             :                "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
     450             :                "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed.\n"
     451           2 :                 + HelpRequiringPassphrase(pwallet) + "\n"
     452             : 
     453             :                "\nArguments:\n"
     454             :                "1. newkeypool (boolean, optional, default true): Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
     455             :                "           If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
     456             :                "           If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
     457             :                "           keypool will be used until it has been depleted."
     458             :                "2. \"seed\" (string, optional, default random seed): The WIF private key to use as the new HD seed.\n"
     459             :                "           The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"
     460           4 :                + HelpExampleCli("sethdseed", "")
     461           4 :                + HelpExampleCli("sethdseed", "false")
     462           4 :                + HelpExampleCli("sethdseed", "true \"wifkey\"")
     463           4 :                + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
     464           3 :         );
     465             : 
     466           8 :     if (IsInitialBlockDownload()) {
     467           0 :         throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
     468             :     }
     469             : 
     470             :     // Make sure the results are valid at least up to the most recent block
     471             :     // the user could have gotten from another RPC command prior to now
     472           8 :     pwallet->BlockUntilSyncedToCurrentChain();
     473             : 
     474          19 :     LOCK2(cs_main, pwallet->cs_wallet);
     475             : 
     476             :     // Do not do anything to non-HD wallets
     477           8 :     if (!pwallet->CanSupportFeature(FEATURE_PRE_SPLIT_KEYPOOL)) {
     478           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Start with -upgradewallet in order to upgrade a non-HD wallet to HD");
     479             :     }
     480             : 
     481           8 :     EnsureWalletIsUnlocked(pwallet);
     482             : 
     483           8 :     bool flush_key_pool = true;
     484           8 :     if (!request.params[0].isNull()) {
     485           7 :         flush_key_pool = request.params[0].get_bool();
     486             :     }
     487             : 
     488           7 :     ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan();
     489           7 :     CPubKey master_pub_key = request.params[1].isNull() ?
     490          17 :             spk_man->GenerateNewSeed() : parseWIFKey(request.params[1].get_str(), pwallet);
     491             : 
     492           3 :     spk_man->SetHDSeed(master_pub_key, true);
     493           3 :     if (flush_key_pool) spk_man->NewKeyPool();
     494             : 
     495             :     // Update Sapling chain
     496           3 :     SaplingScriptPubKeyMan* sspk_man = pwallet->CanSupportFeature(FEATURE_SAPLING) ?
     497           6 :                                        pwallet->GetSaplingScriptPubKeyMan() : nullptr;
     498           3 :     if (sspk_man) {
     499           3 :         sspk_man->SetHDSeed(master_pub_key, true);
     500             :     }
     501             : 
     502           3 :     return NullUniValue;
     503             : }
     504             : 
     505        1091 : UniValue getnewaddress(const JSONRPCRequest& request)
     506             : {
     507        1091 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     508             : 
     509        1091 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     510           0 :         return NullUniValue;
     511             : 
     512        1091 :     if (request.fHelp || request.params.size() > 1)
     513           0 :         throw std::runtime_error(
     514             :             "getnewaddress ( \"label\" )\n"
     515             :             "\nReturns a new PIVX address for receiving payments.\n"
     516             :             "If 'label' is specified, it is added to the address book \n"
     517             :             "so payments received with the address will be associated with 'label'.\n"
     518             : 
     519             :             "\nArguments:\n"
     520             :             "1. \"label\"        (string, optional) The label name for the address to be linked to. if not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n"
     521             : 
     522             :             "\nResult:\n"
     523             :             "\"pivxaddress\"    (string) The new pivx address\n"
     524             : 
     525           0 :             "\nExamples:\n" +
     526           0 :             HelpExampleCli("getnewaddress", "") + HelpExampleRpc("getnewaddress", ""));
     527             : 
     528        2179 :     return EncodeDestination(GetNewAddressFromLabel(pwallet, AddressBook::AddressBookPurpose::RECEIVE, request.params));
     529             : }
     530             : 
     531           2 : UniValue getnewexchangeaddress(const JSONRPCRequest& request)
     532             : {
     533           2 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     534             : 
     535           2 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
     536           0 :         return NullUniValue;
     537             :     }
     538             : 
     539           2 :     if (request.fHelp || request.params.size() > 1)
     540           0 :         throw std::runtime_error(
     541             :             "getnewexchangeaddress ( \"label\" )\n"
     542             :             "\nReturns a new PIVX exchange address for receiving transparent funds only.\n"
     543             : 
     544             :             "\nArguments:\n"
     545             :             "1. \"label\"        (string, optional) The label name for the address to be linked to. if not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n"
     546             : 
     547             : 
     548             :             "\nResult:\n"
     549             :             "\"pivxaddress\"    (string) The new pivx exchange address\n"
     550             : 
     551           0 :             "\nExamples:\n" +
     552           0 :             HelpExampleCli("getnewexchangeaddress", "") + HelpExampleRpc("getnewexchangeaddress", ""));
     553             : 
     554           6 :     LOCK2(cs_main, pwallet->cs_wallet);
     555             : 
     556           4 :     return EncodeDestination(GetNewAddressFromLabel(pwallet, "exchange", request.params, CChainParams::EXCHANGE_ADDRESS), CChainParams::EXCHANGE_ADDRESS);
     557             : }
     558             : 
     559          14 : UniValue getnewstakingaddress(const JSONRPCRequest& request)
     560             : {
     561          14 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     562             : 
     563          14 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     564           0 :         return NullUniValue;
     565             : 
     566          14 :     if (request.fHelp || request.params.size() > 1)
     567           0 :         throw std::runtime_error(
     568             :             "getnewstakingaddress ( \"label\" )\n"
     569             :             "\nReturns a new PIVX cold staking address for receiving delegated cold stakes.\n"
     570             : 
     571             :             "\nArguments:\n"
     572             :             "1. \"label\"        (string, optional) The label name for the address to be linked to. if not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n"
     573             : 
     574             : 
     575             :             "\nResult:\n"
     576             :             "\"pivxaddress\"    (string) The new pivx address\n"
     577             : 
     578           0 :             "\nExamples:\n" +
     579           0 :             HelpExampleCli("getnewstakingaddress", "") + HelpExampleRpc("getnewstakingaddress", ""));
     580             : 
     581          28 :     return EncodeDestination(GetNewAddressFromLabel(pwallet, "coldstaking", request.params, CChainParams::STAKING_ADDRESS), CChainParams::STAKING_ADDRESS);
     582             : }
     583             : 
     584         239 : UniValue getnewshieldaddress(const JSONRPCRequest& request)
     585             : {
     586         239 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     587             : 
     588         239 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     589           0 :         return NullUniValue;
     590             : 
     591         239 :     if (request.fHelp || request.params.size() > 1)
     592           1 :         throw std::runtime_error(
     593             :                 "getnewshieldaddress ( \"label\" )\n"
     594             :                 "\nReturns a new shield address for receiving payments.\n"
     595             :                 "If 'label' is specified, it is added to the address book \n"
     596             :                 "so payments received with the shield address will be associated with 'label'.\n"
     597           2 :                 + HelpRequiringPassphrase(pwallet) + "\n"
     598             : 
     599             :                 "\nArguments:\n"
     600             :                 "1. \"label\"        (string, optional) The label name for the address to be linked to. if not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n"
     601             : 
     602             :                 "\nResult:\n"
     603             :                 "\"address\"    (string) The new shield address.\n"
     604             : 
     605             :                 "\nExamples:\n"
     606           5 :                 + HelpExampleCli("getnewshieldaddress", "")
     607           5 :                 + HelpExampleRpc("getnewshieldaddress", "")
     608           3 :         );
     609             : 
     610         475 :     std::string label;
     611         238 :     if (!request.params.empty()) {
     612           0 :         label = LabelFromValue(request.params[0]);
     613             :     }
     614             : 
     615         714 :     LOCK2(cs_main, pwallet->cs_wallet);
     616             : 
     617         238 :     EnsureWalletIsUnlocked(pwallet);
     618             : 
     619         712 :     return KeyIO::EncodePaymentAddress(pwallet->GenerateNewSaplingZKey(label));
     620             : }
     621             : 
     622         544 : static inline std::string HexStrTrimmed(std::array<unsigned char, ZC_MEMO_SIZE> vch)
     623             : {
     624        1088 :     return HexStr(std::vector<unsigned char>(vch.begin(), FindFirstNonZero(vch.rbegin(), vch.rend()).base()));
     625             : }
     626             : 
     627          21 : UniValue listshieldunspent(const JSONRPCRequest& request)
     628             : {
     629          21 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     630             : 
     631          21 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     632           0 :         return NullUniValue;
     633             : 
     634          21 :     if (request.fHelp || request.params.size() > 4)
     635           1 :         throw std::runtime_error(
     636             :                 "listshieldunspent ( minconf maxconf include_watchonly [\"shield_addr\",...] )\n"
     637             :                 "\nReturns array of unspent shield notes with between minconf and maxconf (inclusive) confirmations.\n"
     638             :                 "Optionally filter to only include notes sent to specified addresses.\n"
     639             :                 "When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n"
     640             : 
     641             :                 "\nArguments:\n"
     642             :                 "1. minconf            (numeric, optional, default=1) The minimum confirmations to filter\n"
     643             :                 "2. maxconf            (numeric, optional, default=9999999) The maximum confirmations to filter\n"
     644             :                 "3. include_watchonly  (bool, optional, default=false) Also include watchonly addresses (see 'importsaplingviewingkey')\n"
     645             :                 "4. \"addresses\"      (string) A json array of shield addrs to filter on.  Duplicate addresses not allowed.\n"
     646             :                 "    [\n"
     647             :                 "      \"address\"     (string) shield addr\n"
     648             :                 "      ,...\n"
     649             :                 "    ]\n"
     650             : 
     651             :                 "\nResult:\n"
     652             :                 "[                             (array of json object)\n"
     653             :                 "  {\n"
     654             :                 "    \"txid\" : \"txid\",          (string) the transaction id \n"
     655             :                 "    \"outindex\" (sapling) : n,       (numeric) the output index\n"
     656             :                 "    \"confirmations\" : n,       (numeric) the number of confirmations\n"
     657             :                 "    \"spendable\" : true|false,  (boolean) true if note can be spent by wallet, false if address is watchonly\n"
     658             :                 "    \"address\" : \"address\",    (string) the shield address\n"
     659             :                 "    \"amount\": xxxxx,          (numeric) the amount of value in the note\n"
     660             :                 "    \"memo\": xxxxx,            (string) hexadecimal string representation of memo field\n"
     661             :                 "    \"change\": true|false,     (boolean) true if the address that received the note is also one of the sending addresses\n"
     662             :                 "    \"nullifier\": xxxxx,       (string) the note's nullifier, hex encoded"
     663             :                 "  }\n"
     664             :                 "  ,...\n"
     665             :                 "]\n"
     666             : 
     667             :                 "\nExamples\n"
     668           3 :                 + HelpExampleCli("listshieldunspent", "")
     669           6 :                 + HelpExampleCli("listshieldunspent", "6 9999999 false \"[\\\"ptestsapling1h0w73csah2aq0a32h42kr7tq4htlt5wfn4ejxfnm56f6ehjvek7k4e244g6v8v3pgylmz5ea8jh\\\",\\\"ptestsapling1h0w73csah2aq0a32h42kr7tq4htlt5wfn4ejxfnm56f6ehjvek7k4e244g6v8v3pgylmz5ea8jh\\\"]\"")
     670           5 :                 + HelpExampleRpc("listshieldunspent", "6 9999999 false \"[\\\"ptestsapling1h0w73csah2aq0a32h42kr7tq4htlt5wfn4ejxfnm56f6ehjvek7k4e244g6v8v3pgylmz5ea8jh\\\",\\\"ptestsapling1h0w73csah2aq0a32h42kr7tq4htlt5wfn4ejxfnm56f6ehjvek7k4e244g6v8v3pgylmz5ea8jh\\\"]\"")
     671           3 :         );
     672             : 
     673          20 :     RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VBOOL, UniValue::VARR});
     674             : 
     675          20 :     int nMinDepth = request.params.size() > 0 ? request.params[0].get_int() : 1;
     676           8 :     if (nMinDepth < 0) {
     677           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
     678             :     }
     679             : 
     680          19 :     int nMaxDepth = request.params.size() > 1 ? request.params[1].get_int() : 9999999;
     681          18 :     if (nMaxDepth < nMinDepth) {
     682           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Maximum number of confirmations must be greater or equal to the minimum number of confirmations");
     683             :     }
     684             : 
     685          31 :     std::set<libzcash::PaymentAddress> shieldAddrs = {};
     686          17 :     bool fIncludeWatchonly = request.params.size() > 2 && request.params[2].get_bool();
     687             : 
     688          51 :     LOCK2(cs_main, pwallet->cs_wallet);
     689             : 
     690             :     // User has supplied shield addrs to filter on
     691          17 :     if (request.params.size() > 3) {
     692           8 :         UniValue addresses = request.params[3].get_array();
     693           5 :         if (addresses.size()==0)
     694           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, addresses array is empty.");
     695             : 
     696             :         // Keep track of addresses to spot duplicates
     697          10 :         std::set<std::string> setAddress;
     698             : 
     699             :         // Sources
     700           7 :         for (const UniValue& o : addresses.getValues()) {
     701           5 :             if (!o.isStr()) {
     702           2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
     703             :             }
     704           8 :             std::string address = o.get_str();
     705           8 :             auto shieldAddr = KeyIO::DecodePaymentAddress(address);
     706           4 :             if (!IsValidPaymentAddress(shieldAddr)) {
     707           2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, address is not a valid shield address: ") + address);
     708             :             }
     709           3 :             libzcash::SaplingPaymentAddress paymentAddress = *boost::get<libzcash::SaplingPaymentAddress>(&shieldAddr);
     710           3 :             bool hasSpendingKey = pwallet->HaveSpendingKeyForPaymentAddress(paymentAddress);
     711           3 :             if (!fIncludeWatchonly && !hasSpendingKey) {
     712           2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, spending key for address does not belong to wallet: ") + address);
     713             :             }
     714           2 :             shieldAddrs.insert(shieldAddr);
     715             : 
     716           2 :             if (setAddress.count(address)) {
     717           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + address);
     718             :             }
     719           2 :             setAddress.insert(address);
     720             :         }
     721             :     } else {
     722             :         // User did not provide shield addrs, so use default i.e. all addresses
     723          24 :         std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
     724          12 :         pwallet->GetSaplingPaymentAddresses(saplingzaddrs);
     725          12 :         shieldAddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
     726             :     }
     727             : 
     728          28 :     UniValue results(UniValue::VARR);
     729             : 
     730          14 :     if (shieldAddrs.size() > 0) {
     731          28 :         std::vector<SaplingNoteEntry> saplingEntries;
     732          14 :         pwallet->GetSaplingScriptPubKeyMan()->GetFilteredNotes(saplingEntries, shieldAddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
     733          28 :         std::set<std::pair<libzcash::PaymentAddress, uint256>> nullifierSet = pwallet->GetSaplingScriptPubKeyMan()->GetNullifiersForAddresses(shieldAddrs);
     734             : 
     735         517 :         for (const auto& entry : saplingEntries) {
     736        1006 :             UniValue obj(UniValue::VOBJ);
     737        1006 :             obj.pushKV("txid", entry.op.hash.ToString());
     738         503 :             obj.pushKV("outindex", (int)entry.op.n);
     739         503 :             obj.pushKV("confirmations", entry.confirmations);
     740         503 :             bool hasSaplingSpendingKey = pwallet->HaveSpendingKeyForPaymentAddress(entry.address);
     741         503 :             obj.pushKV("spendable", hasSaplingSpendingKey);
     742        1509 :             obj.pushKV("address", KeyIO::EncodePaymentAddress(entry.address));
     743        1006 :             obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
     744        1006 :             obj.pushKV("memo", HexStrTrimmed(entry.memo));
     745         503 :             if (hasSaplingSpendingKey) {
     746        1006 :                 obj.pushKV("change", pwallet->GetSaplingScriptPubKeyMan()->IsNoteSaplingChange(nullifierSet, entry.address, entry.op));
     747             :             }
     748         503 :             const auto& nd = pwallet->mapWallet.at(entry.op.hash).mapSaplingNoteData.at(entry.op);
     749         503 :             if (nd.nullifier) {
     750        1509 :                 obj.pushKV("nullifier", nd.nullifier->ToString());
     751             :             }
     752         503 :             results.push_back(obj);
     753             :         }
     754             :     }
     755             : 
     756          14 :     return results;
     757             : }
     758             : 
     759           2 : UniValue delegatoradd(const JSONRPCRequest& request)
     760             : {
     761           2 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     762             : 
     763           2 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     764           0 :         return NullUniValue;
     765             : 
     766           2 :     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
     767           0 :         throw std::runtime_error(
     768             :             "delegatoradd \"address\" ( \"label\" )\n"
     769             :             "\nAdd the provided address <address> into the allowed delegators AddressBook.\n"
     770             :             "This enables the staking of coins delegated to this wallet, owned by <addr>\n"
     771             : 
     772             :             "\nArguments:\n"
     773             :             "1. \"address\"     (string, required) The address to whitelist\n"
     774             :             "2. \"label\"       (string, optional) A label for the address to whitelist\n"
     775             : 
     776             :             "\nResult:\n"
     777             :             "true|false           (boolean) true if successful.\n"
     778             : 
     779           0 :             "\nExamples:\n" +
     780           0 :             HelpExampleCli("delegatoradd", "DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6") +
     781           0 :             HelpExampleRpc("delegatoradd", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\"") +
     782           0 :             HelpExampleRpc("delegatoradd", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" \"myPaperWallet\""));
     783             : 
     784           2 :     bool isStaking = false;
     785           2 :     bool isExchange = false;
     786           4 :     CTxDestination dest = DecodeDestination(request.params[0].get_str(), isStaking, isExchange);
     787           2 :     if (!IsValidDestination(dest) || isStaking)
     788           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
     789             : 
     790           4 :     const std::string strLabel = (request.params.size() > 1 ? request.params[1].get_str() : "");
     791             : 
     792           2 :     const CKeyID* keyID = boost::get<CKeyID>(&dest);
     793           2 :     if (!keyID)
     794           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get KeyID from PIVX address");
     795             : 
     796           4 :     return pwallet->SetAddressBook(*keyID, strLabel, AddressBook::AddressBookPurpose::DELEGATOR);
     797             : }
     798             : 
     799           1 : UniValue delegatorremove(const JSONRPCRequest& request)
     800             : {
     801           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     802             : 
     803           1 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     804           0 :         return NullUniValue;
     805             : 
     806           1 :     if (request.fHelp || request.params.size() != 1)
     807           0 :         throw std::runtime_error(
     808             :             "delegatorremove \"address\"\n"
     809             :             "\nUpdates the provided address <address> from the allowed delegators keystore to a \"delegable\" status.\n"
     810             :             "This disables the staking of coins delegated to this wallet, owned by <addr>\n"
     811             : 
     812             :             "\nArguments:\n"
     813             :             "1. \"address\"      (string, required) The address to blacklist\n"
     814             : 
     815             :             "\nResult:\n"
     816             :             "true|false           (boolean) true if successful.\n"
     817             : 
     818           0 :             "\nExamples:\n" +
     819           0 :             HelpExampleCli("delegatorremove", "DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6") +
     820           0 :             HelpExampleRpc("delegatorremove", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\""));
     821             : 
     822           1 :     bool isStaking = false;
     823           1 :     bool isExchange = false;
     824           2 :     CTxDestination dest = DecodeDestination(request.params[0].get_str(), isStaking, isExchange);
     825           1 :     if (!IsValidDestination(dest) || isStaking)
     826           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
     827             : 
     828           1 :     const CKeyID* keyID = boost::get<CKeyID>(&dest);
     829           1 :     if (!keyID)
     830           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get KeyID from PIVX address");
     831             : 
     832           1 :     if (!pwallet->HasAddressBook(*keyID))
     833           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get PIVX address from addressBook");
     834             : 
     835           2 :     std::string label = "";
     836           2 :     auto optAdd = pwallet->GetAddressBookEntry(dest);
     837           1 :     if (optAdd) {
     838           1 :         label = optAdd->name;
     839             :     }
     840             : 
     841           2 :     return pwallet->SetAddressBook(*keyID, label, AddressBook::AddressBookPurpose::DELEGABLE);
     842             : }
     843             : 
     844           6 : static UniValue ListaddressesForPurpose(CWallet* const pwallet, const std::string strPurpose)
     845             : {
     846           6 :     CChainParams::Base58Type addrType;
     847           6 :     if (AddressBook::IsColdStakingPurpose(strPurpose)) {
     848             :         addrType = CChainParams::STAKING_ADDRESS;
     849           5 :     } else if (AddressBook::IsExchangePurpose(strPurpose)) {
     850             :         addrType = CChainParams::EXCHANGE_ADDRESS;
     851             :     } else {
     852           5 :         addrType = CChainParams::PUBKEY_ADDRESS;
     853             :     }
     854           6 :     UniValue ret(UniValue::VARR);
     855           6 :     {
     856           6 :         LOCK(pwallet->cs_wallet);
     857          38 :         for (auto it = pwallet->NewAddressBookIterator(); it.IsValid(); it.Next()) {
     858          17 :             auto addrBook = it.GetValue();
     859          13 :             if (addrBook.purpose != strPurpose) continue;
     860           4 :             auto dest = it.GetCTxDestKey();
     861           4 :             if (!dest) continue;
     862           8 :             UniValue entry(UniValue::VOBJ);
     863           4 :             entry.pushKV("label", addrBook.name);
     864           8 :             entry.pushKV("address", EncodeDestination(*dest, addrType));
     865           4 :             ret.push_back(entry);
     866             :         }
     867             :     }
     868             : 
     869           6 :     return ret;
     870             : }
     871             : 
     872           5 : UniValue listdelegators(const JSONRPCRequest& request)
     873             : {
     874           5 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     875             : 
     876           5 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     877           0 :         return NullUniValue;
     878             : 
     879           5 :     if (request.fHelp || request.params.size() > 1)
     880           0 :         throw std::runtime_error(
     881             :             "listdelegators ( blacklist )\n"
     882             :             "\nShows the list of allowed delegator addresses for cold staking.\n"
     883             : 
     884             :             "\nArguments:\n"
     885             :             "1. blacklist             (boolean, optional, default = false) Show addresses removed\n"
     886             :             "                          from the delegators whitelist\n"
     887             : 
     888             :             "\nResult:\n"
     889             :             "[\n"
     890             :             "   {\n"
     891             :             "   \"label\": \"yyy\",    (string) Address label\n"
     892             :             "   \"address\": \"xxx\",  (string) PIVX address string\n"
     893             :             "   }\n"
     894             :             "  ...\n"
     895             :             "]\n"
     896             : 
     897           0 :             "\nExamples:\n" +
     898           0 :             HelpExampleCli("listdelegators" , "") +
     899           0 :             HelpExampleRpc("listdelegators", ""));
     900             : 
     901           5 :     const bool fBlacklist = (request.params.size() > 0 ? request.params[0].get_bool() : false);
     902           5 :     return (fBlacklist ?
     903             :             ListaddressesForPurpose(pwallet, AddressBook::AddressBookPurpose::DELEGABLE) :
     904          10 :             ListaddressesForPurpose(pwallet, AddressBook::AddressBookPurpose::DELEGATOR));
     905             : }
     906             : 
     907           1 : UniValue liststakingaddresses(const JSONRPCRequest& request)
     908             : {
     909           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     910             : 
     911           1 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     912           0 :         return NullUniValue;
     913             : 
     914           1 :     if (request.fHelp || !request.params.empty())
     915           0 :         throw std::runtime_error(
     916             :             "liststakingaddresses\n"
     917             :             "\nShows the list of staking addresses for this wallet.\n"
     918             : 
     919             :             "\nResult:\n"
     920             :             "[\n"
     921             :             "   {\n"
     922             :             "   \"label\": \"yyy\",  (string) Address label\n"
     923             :             "   \"address\": \"xxx\",  (string) PIVX address string\n"
     924             :             "   }\n"
     925             :             "  ...\n"
     926             :             "]\n"
     927             : 
     928           0 :             "\nExamples:\n" +
     929           0 :             HelpExampleCli("liststakingaddresses" , "") +
     930           0 :             HelpExampleRpc("liststakingaddresses", ""));
     931             : 
     932           2 :     return ListaddressesForPurpose(pwallet, AddressBook::AddressBookPurpose::COLD_STAKING);
     933             : }
     934             : 
     935          13 : UniValue listshieldaddresses(const JSONRPCRequest& request)
     936             : {
     937          13 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     938             : 
     939          13 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     940           0 :         return NullUniValue;
     941             : 
     942          13 :     if (request.fHelp || request.params.size() > 1)
     943           0 :         throw std::runtime_error(
     944             :                 "listshieldaddresses ( include_watchonly )\n"
     945             :                 "\nReturns the list of shield addresses belonging to the wallet.\n"
     946             : 
     947             :                 "\nArguments:\n"
     948             :                 "1. include_watchonly (bool, optional, default=false) Also include watchonly addresses (see 'importviewingkey')\n"
     949             : 
     950             :                 "\nResult:\n"
     951             :                 "[                     (json array of string)\n"
     952             :                 "  \"addr\"           (string) a shield address belonging to the wallet\n"
     953             :                 "  ,...\n"
     954             :                 "]\n"
     955             : 
     956             :                 "\nExamples:\n"
     957           0 :                 + HelpExampleCli("listshieldaddresses", "")
     958           0 :                 + HelpExampleRpc("listshieldaddresses", "")
     959           0 :         );
     960             : 
     961          39 :     LOCK2(cs_main, pwallet->cs_wallet);
     962             : 
     963          13 :     bool fIncludeWatchonly = false;
     964          13 :     if (request.params.size() > 0) {
     965           1 :         fIncludeWatchonly = request.params[0].get_bool();
     966             :     }
     967             : 
     968          26 :     UniValue ret(UniValue::VARR);
     969             : 
     970          26 :     std::set<libzcash::SaplingPaymentAddress> addresses;
     971          13 :     pwallet->GetSaplingPaymentAddresses(addresses);
     972          13 :     libzcash::SaplingIncomingViewingKey ivk;
     973          13 :     libzcash::SaplingExtendedFullViewingKey extfvk;
     974        3323 :     for (libzcash::SaplingPaymentAddress addr : addresses) {
     975        3310 :         if (fIncludeWatchonly || pwallet->HaveSpendingKeyForPaymentAddress(addr)) {
     976        6618 :             ret.push_back(KeyIO::EncodePaymentAddress(addr));
     977             :         }
     978             :     }
     979          13 :     return ret;
     980             : }
     981             : 
     982          10 : UniValue getrawchangeaddress(const JSONRPCRequest& request)
     983             : {
     984          10 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     985             : 
     986          10 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     987           0 :         return NullUniValue;
     988             : 
     989          10 :     if (request.fHelp || !request.params.empty())
     990           0 :         throw std::runtime_error(
     991             :             "getrawchangeaddress\n"
     992             :             "\nReturns a new PIVX address, for receiving change.\n"
     993             :             "This is for use with raw transactions, NOT normal use.\n"
     994             : 
     995             :             "\nResult:\n"
     996             :             "\"address\"    (string) The address\n"
     997             : 
     998           0 :             "\nExamples:\n" +
     999           0 :             HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", ""));
    1000             : 
    1001          29 :     LOCK2(cs_main, pwallet->cs_wallet);
    1002             : 
    1003          10 :     if (!pwallet->IsLocked())
    1004           2 :         pwallet->TopUpKeyPool();
    1005             : 
    1006          20 :     CReserveKey reservekey(pwallet);
    1007          10 :     CPubKey vchPubKey;
    1008          10 :     if (!reservekey.GetReservedKey(vchPubKey, true))
    1009           2 :         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
    1010             : 
    1011           9 :     reservekey.KeepKey();
    1012             : 
    1013           9 :     CKeyID keyID = vchPubKey.GetID();
    1014             : 
    1015          19 :     return EncodeDestination(keyID);
    1016             : }
    1017             : 
    1018             : 
    1019          18 : UniValue setlabel(const JSONRPCRequest& request)
    1020             : {
    1021          18 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1022             : 
    1023          18 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1024           0 :         return NullUniValue;
    1025             : 
    1026          18 :     if (request.fHelp || request.params.size() != 2)
    1027           0 :         throw std::runtime_error(
    1028             :             "setlabel \"address\" \"label\"\n"
    1029             :             "\nSets the label associated with the given address.\n"
    1030             : 
    1031             :             "\nArguments:\n"
    1032             :             "1. \"address\"       (string, required) The pivx address to be associated with a label.\n"
    1033             :             "2. \"label\"         (string, required) The label to assign to the address.\n"
    1034             : 
    1035           0 :             "\nExamples:\n" +
    1036           0 :             HelpExampleCli("setlabel", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" \"tabby\"") + HelpExampleRpc("setlabel", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\", \"tabby\""));
    1037             : 
    1038          54 :     LOCK2(cs_main, pwallet->cs_wallet);
    1039             : 
    1040          18 :     bool isStaking = false, isExchange = false, isShielded = false;
    1041          36 :     const CWDestination& dest = Standard::DecodeDestination(request.params[0].get_str(), isStaking, isExchange, isShielded);
    1042             :     // Make sure the destination is valid
    1043          18 :     if (!Standard::IsValidDestination(dest)) {
    1044           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
    1045             :     }
    1046             : 
    1047          36 :     std::string old_label = pwallet->GetNameForAddressBookEntry(dest);
    1048          36 :     std::string label = LabelFromValue(request.params[1]);
    1049             : 
    1050          18 :     pwallet->SetAddressBook(dest, label, "");
    1051             : 
    1052          18 :     return NullUniValue;
    1053             : }
    1054             : 
    1055         244 : static void SendMoney(CWallet* const pwallet, const CTxDestination& address, CAmount nValue, bool fSubtractFeeFromAmount, CTransactionRef& tx)
    1056             : {
    1057         488 :     LOCK2(cs_main, pwallet->cs_wallet);
    1058             : 
    1059             :     // Check amount
    1060         244 :     if (nValue <= 0)
    1061           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
    1062             : 
    1063         244 :     if (nValue > pwallet->GetAvailableBalance())
    1064           0 :         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
    1065             : 
    1066         244 :     if (!g_connman)
    1067           0 :         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
    1068             : 
    1069             :     // Parse PIVX address
    1070         488 :     CScript scriptPubKey = GetScriptForDestination(address);
    1071             : 
    1072             :     // Create and send the transaction
    1073         488 :     CReserveKey reservekey(pwallet);
    1074         244 :     CAmount nFeeRequired;
    1075         488 :     std::string strError;
    1076         488 :     std::vector<CRecipient> vecSend;
    1077         244 :     int nChangePosRet = -1;
    1078         488 :     CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
    1079         244 :     vecSend.push_back(recipient);
    1080         244 :     if (!pwallet->CreateTransaction(vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError)) {
    1081           1 :         if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwallet->GetAvailableBalance())
    1082           0 :             strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
    1083           1 :         LogPrintf("%s: %s\n", __func__, strError);
    1084           1 :         throw JSONRPCError(RPC_WALLET_ERROR, strError);
    1085             :     }
    1086         487 :     const CWallet::CommitResult&& res = pwallet->CommitTransaction(tx, reservekey, g_connman.get());
    1087         243 :     if (res.status != CWallet::CommitStatus::OK)
    1088           0 :         throw JSONRPCError(RPC_WALLET_ERROR, res.ToString());
    1089         243 : }
    1090             : 
    1091             : static SaplingOperation CreateShieldedTransaction(CWallet* const pwallet, const JSONRPCRequest& request);
    1092             : 
    1093             : /*
    1094             :  * redirect sendtoaddress/sendmany inputs to shieldsendmany implementation (CreateShieldedTransaction)
    1095             :  */
    1096          17 : static UniValue ShieldSendManyTo(CWallet * const pwallet,
    1097             :                                  const UniValue& sendTo,
    1098             :                                  const std::string& commentStr,
    1099             :                                  const std::string& toStr,
    1100             :                                  int nMinDepth,
    1101             :                                  bool fIncludeDelegated,
    1102             :                                  UniValue subtractFeeFromAmount)
    1103             : {
    1104             :     // convert params to 'shieldsendmany' format
    1105          34 :     JSONRPCRequest req;
    1106          17 :     req.params = UniValue(UniValue::VARR);
    1107          17 :     if (!fIncludeDelegated) {
    1108          17 :         req.params.push_back(UniValue("from_transparent"));
    1109             :     } else {
    1110           0 :         req.params.push_back(UniValue("from_trans_cold"));
    1111             :     }
    1112          34 :     UniValue recipients(UniValue::VARR);
    1113          37 :     for (const std::string& key : sendTo.getKeys()) {
    1114          40 :         UniValue recipient(UniValue::VOBJ);
    1115          20 :         recipient.pushKV("address", key);
    1116          20 :         recipient.pushKV("amount", sendTo[key]);
    1117          20 :         recipients.push_back(recipient);
    1118             :     }
    1119          17 :     req.params.push_back(recipients);
    1120          17 :     req.params.push_back(nMinDepth);
    1121          17 :     req.params.push_back(0);
    1122          17 :     req.params.push_back(subtractFeeFromAmount);
    1123             : 
    1124             :     // send
    1125          17 :     SaplingOperation operation = CreateShieldedTransaction(pwallet, req);
    1126          34 :     std::string txid;
    1127          34 :     auto res = operation.send(txid);
    1128          17 :     if (!res)
    1129           0 :         throw JSONRPCError(RPC_WALLET_ERROR, res.getError());
    1130             : 
    1131             :     // add comments
    1132          17 :     const uint256& txHash = uint256S(txid);
    1133          17 :     auto it = pwallet->mapWallet.find(txHash);
    1134          17 :     assert(it != pwallet->mapWallet.end());
    1135          17 :     if (!commentStr.empty()) {
    1136           0 :         it->second.mapValue["comment"] = commentStr;
    1137             :     }
    1138          17 :     if (!toStr.empty()) {
    1139           0 :         it->second.mapValue["to"] = toStr;
    1140             :     }
    1141             : 
    1142          34 :     return txid;
    1143             : }
    1144             : 
    1145         260 : UniValue sendtoaddress(const JSONRPCRequest& request)
    1146             : {
    1147         260 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1148             : 
    1149         260 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1150           0 :         return NullUniValue;
    1151             : 
    1152         260 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
    1153           0 :         throw std::runtime_error(
    1154             :             "sendtoaddress \"address\" amount ( \"comment\" \"comment-to\" subtract_fee )\n"
    1155           0 :             "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" +
    1156           0 :             HelpRequiringPassphrase(pwallet) + "\n"
    1157             : 
    1158             :             "\nArguments:\n"
    1159             :             "1. \"address\"     (string, required) The pivx address to send to.\n"
    1160             :             "2. \"amount\"      (numeric, required) The amount in PIV to send. eg 0.1\n"
    1161             :             "3. \"comment\"     (string, optional) A comment used to store what the transaction is for. \n"
    1162             :             "                             This is not part of the transaction, just kept in your wallet.\n"
    1163             :             "4. \"comment-to\"  (string, optional) A comment to store the name of the person or organization \n"
    1164             :             "                             to which you're sending the transaction. This is not part of the \n"
    1165             :             "                             transaction, just kept in your wallet.\n"
    1166             :             "5. subtract_fee    (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
    1167             :             "                             The recipient will receive less PIVs than you enter in the amount field.\n"
    1168             : 
    1169             :             "\nResult:\n"
    1170             :             "\"transactionid\"  (string) The transaction id.\n"
    1171             : 
    1172           0 :             "\nExamples:\n" +
    1173           0 :             HelpExampleCli("sendtoaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" 0.1") +
    1174           0 :             HelpExampleCli("sendtoaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" 0.1 \"donation\" \"seans outpost\"") +
    1175           0 :             HelpExampleCli("sendtoaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" 0.1 \"\" \"\" true") +
    1176           0 :             HelpExampleRpc("sendtoaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\", 0.1, \"donation\", \"seans outpost\""));
    1177             : 
    1178         260 :     EnsureWalletIsUnlocked(pwallet);
    1179             : 
    1180             :     // Make sure the results are valid at least up to the most recent block
    1181             :     // the user could have gotten from another RPC command prior to now
    1182         259 :     pwallet->BlockUntilSyncedToCurrentChain();
    1183             : 
    1184         259 :     bool isStaking = false, isExchange = false, isShielded = false;
    1185         517 :     const std::string addrStr = request.params[0].get_str();
    1186         518 :     const CWDestination& destination = Standard::DecodeDestination(addrStr, isStaking, isExchange, isShielded);
    1187         259 :     if (!Standard::IsValidDestination(destination) || isStaking)
    1188           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
    1189         259 :     const std::string commentStr = (request.params.size() > 2 && !request.params[2].isNull()) ?
    1190         522 :                                    request.params[2].get_str() : "";
    1191         259 :     const std::string toStr = (request.params.size() > 3 && !request.params[3].isNull()) ?
    1192         522 :                                    request.params[3].get_str() : "";
    1193         259 :     bool fSubtractFeeFromAmount = request.params.size() > 4 && request.params[4].get_bool();
    1194             : 
    1195         259 :     if (isShielded) {
    1196          30 :         UniValue sendTo(UniValue::VOBJ);
    1197          15 :         sendTo.pushKV(addrStr, request.params[1]);
    1198          15 :         UniValue subtractFeeFromAmount(UniValue::VARR);
    1199          15 :         if (fSubtractFeeFromAmount) {
    1200           1 :             subtractFeeFromAmount.push_back(addrStr);
    1201             :         }
    1202          15 :         return ShieldSendManyTo(pwallet, sendTo, commentStr, toStr, 1, false, subtractFeeFromAmount);
    1203             :     }
    1204             : 
    1205         244 :     const CTxDestination& address = *Standard::GetTransparentDestination(destination);
    1206             : 
    1207             :     // Amount
    1208         244 :     CAmount nAmount = AmountFromValue(request.params[1]);
    1209             : 
    1210         259 :     CTransactionRef tx;
    1211         244 :     SendMoney(pwallet, address, nAmount, fSubtractFeeFromAmount, tx);
    1212             : 
    1213             :     // Wallet comments
    1214         243 :     CWalletTx& wtx = pwallet->mapWallet.at(tx->GetHash());
    1215         243 :     if (!commentStr.empty())
    1216           0 :         wtx.mapValue["comment"] = commentStr;
    1217         243 :     if (!toStr.empty())
    1218           0 :         wtx.mapValue["to"] = toStr;
    1219             : 
    1220         487 :     return wtx.GetHash().GetHex();
    1221             : }
    1222             : 
    1223          33 : static UniValue CreateColdStakeDelegation(CWallet* const pwallet, const UniValue& params, CTransactionRef& txNew, CReserveKey& reservekey)
    1224             : {
    1225          66 :     LOCK2(cs_main, pwallet->cs_wallet);
    1226             : 
    1227             :     // Check that Cold Staking has been enforced or fForceNotEnabled = true
    1228          33 :     bool fForceNotEnabled = false;
    1229          33 :     if (params.size() > 6 && !params[6].isNull())
    1230           1 :         fForceNotEnabled = params[6].get_bool();
    1231             : 
    1232          33 :     if (sporkManager.IsSporkActive(SPORK_19_COLDSTAKING_MAINTENANCE) && !fForceNotEnabled) {
    1233           0 :         std::string errMsg = "Cold Staking temporarily disabled with SPORK 19.\n"
    1234             :                 "You may force the stake delegation setting fForceNotEnabled to true.\n"
    1235           2 :                 "WARNING: If relayed before activation, this tx will be rejected resulting in a ban.\n";
    1236           0 :         throw JSONRPCError(RPC_WALLET_ERROR, errMsg);
    1237             :     }
    1238             : 
    1239             :     // Get Staking Address
    1240          33 :     bool isStaking{false};
    1241          66 :     CTxDestination stakeAddr = DecodeDestination(params[0].get_str());
    1242          33 :     if (!IsValidDestination(stakeAddr) || isStaking)
    1243           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX staking address");
    1244             : 
    1245          33 :     CKeyID* stakeKey = boost::get<CKeyID>(&stakeAddr);
    1246          33 :     if (!stakeKey)
    1247           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Unable to get stake pubkey hash from stakingaddress");
    1248             : 
    1249             :     // Get Amount
    1250          33 :     CAmount nValue = AmountFromValue(params[1]);
    1251          33 :     if (nValue < MIN_COLDSTAKING_AMOUNT)
    1252           1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid amount (%d). Min amount: %d",
    1253           3 :                 nValue, MIN_COLDSTAKING_AMOUNT));
    1254             : 
    1255             :     // include already delegated coins
    1256          32 :     bool fUseDelegated = false;
    1257          32 :     if (params.size() > 4 && !params[4].isNull())
    1258           2 :         fUseDelegated = params[4].get_bool();
    1259             : 
    1260             :     // Check amount
    1261          32 :     CAmount currBalance = pwallet->GetAvailableBalance() + (fUseDelegated ? pwallet->GetDelegatedBalance() : 0);
    1262          32 :     if (nValue > currBalance)
    1263           0 :         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
    1264             : 
    1265          64 :     std::string strError;
    1266             : 
    1267             :     // Get Owner Address
    1268          32 :     std::string ownerAddressStr;
    1269          32 :     CKeyID ownerKey;
    1270          32 :     bool isStakingAddress = false;
    1271          32 :     bool isExchange = false;
    1272          32 :     if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty()) {
    1273             :         // Address provided
    1274          48 :         CTxDestination dest = DecodeDestination(params[2].get_str(), isStakingAddress, isExchange);
    1275          24 :         if (!IsValidDestination(dest) || isStakingAddress)
    1276           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX spending address");
    1277          24 :         ownerKey = *boost::get<CKeyID>(&dest);
    1278             :         // Check that the owner address belongs to this wallet, or fForceExternalAddr is true
    1279          24 :         bool fForceExternalAddr = params.size() > 3 && !params[3].isNull() ? params[3].get_bool() : false;
    1280          23 :         if (!fForceExternalAddr && !pwallet->HaveKey(ownerKey)) {
    1281           2 :             std::string errMsg = strprintf("The provided owneraddress \"%s\" is not present in this wallet.\n", params[2].get_str());
    1282           1 :             errMsg += "Set 'fExternalOwner' argument to true, in order to force the stake delegation to an external owner address.\n"
    1283             :                     "e.g. delegatestake stakingaddress amount owneraddress true.\n"
    1284           1 :                     "WARNING: Only the owner of the key to owneraddress will be allowed to spend these coins after the delegation.";
    1285           1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errMsg);
    1286             :         }
    1287          23 :         ownerAddressStr = params[2].get_str();
    1288             :     } else {
    1289             :         // Get new owner address from keypool
    1290          16 :         CTxDestination ownerAddr = GetNewAddressFromLabel(pwallet, "delegated", NullUniValue);
    1291           8 :         CKeyID* pOwnerKey = boost::get<CKeyID>(&ownerAddr);
    1292           8 :         assert(pOwnerKey);
    1293           8 :         ownerKey = *pOwnerKey;
    1294           8 :         ownerAddressStr = EncodeDestination(ownerAddr);
    1295             :     }
    1296             : 
    1297             :     // Use new opcode after v6.0 enforcement (!TODO: remove after enforcement)
    1298          31 :     bool fV6Enforced = Params().GetConsensus().NetworkUpgradeActive(chainActive.Height(), Consensus::UPGRADE_V6_0);
    1299             : 
    1300             :     // Create the transaction
    1301          31 :     const bool fUseShielded = (params.size() > 5) && params[5].get_bool();
    1302          31 :     if (!fUseShielded) {
    1303             :         // Delegate transparent coins
    1304          30 :         CAmount nFeeRequired;
    1305          30 :         CScript scriptPubKey = fV6Enforced ? GetScriptForStakeDelegation(*stakeKey, ownerKey)
    1306          60 :                                            : GetScriptForStakeDelegationLOF(*stakeKey, ownerKey);
    1307          60 :         if (!pwallet->CreateTransaction(scriptPubKey, nValue, txNew, reservekey, nFeeRequired, strError, nullptr, (CAmount)0, fUseDelegated)) {
    1308           0 :             if (nValue + nFeeRequired > currBalance)
    1309           0 :                 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
    1310           0 :             LogPrintf("%s : %s\n", __func__, strError);
    1311           0 :             throw JSONRPCError(RPC_WALLET_ERROR, strError);
    1312             :         }
    1313             :     } else {
    1314             :         // Delegate shield coins
    1315           1 :         const Consensus::Params& consensus = Params().GetConsensus();
    1316             :         // Check network status
    1317           1 :         if (sporkManager.IsSporkActive(SPORK_20_SAPLING_MAINTENANCE)) {
    1318           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "SHIELD in maintenance (SPORK 20)");
    1319             :         }
    1320           4 :         std::vector<SendManyRecipient> recipients = {SendManyRecipient(ownerKey, *stakeKey, nValue, fV6Enforced)};
    1321           1 :         SaplingOperation operation(consensus, pwallet);
    1322           1 :         OperationResult res = operation.setSelectShieldedCoins(true)
    1323             :                                        ->setRecipients(recipients)
    1324           2 :                                        ->build();
    1325           1 :         if (!res) throw JSONRPCError(RPC_WALLET_ERROR, res.getError());
    1326           1 :         txNew = MakeTransactionRef(operation.getFinalTx());
    1327             :     }
    1328             : 
    1329          31 :     UniValue result(UniValue::VOBJ);
    1330          31 :     result.pushKV("owner_address", ownerAddressStr);
    1331          62 :     result.pushKV("staker_address", EncodeDestination(stakeAddr, true, false));
    1332          62 :     return result;
    1333             : }
    1334             : 
    1335          31 : UniValue delegatestake(const JSONRPCRequest& request)
    1336             : {
    1337          31 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1338             : 
    1339          31 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1340           0 :         return NullUniValue;
    1341             : 
    1342          31 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 7)
    1343           0 :         throw std::runtime_error(
    1344             :             "delegatestake \"staking_addr\" amount ( \"owner_addr\" ext_owner include_delegated from_shield force )\n"
    1345           0 :             "\nDelegate an amount to a given address for cold staking. The amount is a real and is rounded to the nearest 0.00000001\n" +
    1346           0 :             HelpRequiringPassphrase(pwallet) + "\n"
    1347             : 
    1348             :             "\nArguments:\n"
    1349             :             "1. \"staking_addr\"      (string, required) The pivx staking address to delegate.\n"
    1350             :             "2. \"amount\"            (numeric, required) The amount in PIV to delegate for staking. eg 100\n"
    1351             :             "3. \"owner_addr\"        (string, optional) The pivx address corresponding to the key that will be able to spend the stake.\n"
    1352             :             "                               If not provided, or empty string, a new wallet address is generated.\n"
    1353             :             "4. \"ext_owner\"         (boolean, optional, default = false) use the provided 'owneraddress' anyway, even if not present in this wallet.\n"
    1354             :             "                               WARNING: The owner of the keys to 'owneraddress' will be the only one allowed to spend these coins.\n"
    1355             :             "5. \"include_delegated\" (boolean, optional, default = false) include already delegated inputs if needed.\n"
    1356             :             "6. \"from_shield\"       (boolean, optional, default = false) delegate shield funds.\n"
    1357             :             "7. \"force\"             (boolean, optional, default = false) ONLY FOR TESTING: force the creation even if SPORK 17 is disabled.\n"
    1358             : 
    1359             :             "\nResult:\n"
    1360             :             "{\n"
    1361             :             "   \"owner_address\": \"xxx\"   (string) The owner (delegator) owneraddress.\n"
    1362             :             "   \"staker_address\": \"xxx\"  (string) The cold staker (delegate) stakingaddress.\n"
    1363             :             "   \"txid\": \"xxx\"            (string) The stake delegation transaction id.\n"
    1364             :             "}\n"
    1365             : 
    1366           0 :             "\nExamples:\n" +
    1367           0 :             HelpExampleCli("delegatestake", "\"S1t2a3kab9c8c71VA78xxxy4MxZg6vgeS6\" 100") +
    1368           0 :             HelpExampleCli("delegatestake", "\"S1t2a3kab9c8c71VA78xxxy4MxZg6vgeS6\" 1000 \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg34fk\"") +
    1369           0 :             HelpExampleRpc("delegatestake", "\"S1t2a3kab9c8c71VA78xxxy4MxZg6vgeS6\", 1000, \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg34fk\""));
    1370             : 
    1371          31 :     EnsureWalletIsUnlocked(pwallet);
    1372             : 
    1373             :     // Make sure the results are valid at least up to the most recent block
    1374             :     // the user could have gotten from another RPC command prior to now
    1375          31 :     pwallet->BlockUntilSyncedToCurrentChain();
    1376             : 
    1377          90 :     LOCK2(cs_main, pwallet->cs_wallet);
    1378             : 
    1379          31 :     CTransactionRef wtx;
    1380          62 :     CReserveKey reservekey(pwallet);
    1381          59 :     UniValue ret = CreateColdStakeDelegation(pwallet, request.params, wtx, reservekey);
    1382             : 
    1383          58 :     const CWallet::CommitResult& res = pwallet->CommitTransaction(wtx, reservekey, g_connman.get());
    1384          29 :     if (res.status != CWallet::CommitStatus::OK)
    1385           2 :         throw JSONRPCError(RPC_WALLET_ERROR, res.ToString());
    1386             : 
    1387          57 :     ret.pushKV("txid", wtx->GetHash().GetHex());
    1388          28 :     return ret;
    1389             : }
    1390             : 
    1391           2 : UniValue rawdelegatestake(const JSONRPCRequest& request)
    1392             : {
    1393           2 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1394             : 
    1395           2 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1396           0 :         return NullUniValue;
    1397             : 
    1398           2 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 7)
    1399           0 :         throw std::runtime_error(
    1400             :             "rawdelegatestake \"staking_addr\" amount ( \"owner_addr\" ext_owner include_delegated from_shield )\n"
    1401             :             "\nDelegate an amount to a given address for cold staking. The amount is a real and is rounded to the nearest 0.00000001\n"
    1402           0 :             "\nDelegate transaction is returned as json object." +
    1403           0 :             HelpRequiringPassphrase(pwallet) + "\n"
    1404             : 
    1405             :             "\nArguments:\n"
    1406             :             "1. \"staking_addr\"      (string, required) The pivx staking address to delegate.\n"
    1407             :             "2. \"amount\"            (numeric, required) The amount in PIV to delegate for staking. eg 100\n"
    1408             :             "3. \"owner_addr\"        (string, optional) The pivx address corresponding to the key that will be able to spend the stake.\n"
    1409             :             "                               If not provided, or empty string, a new wallet address is generated.\n"
    1410             :             "4. \"ext_owner\"         (boolean, optional, default = false) use the provided 'owneraddress' anyway, even if not present in this wallet.\n"
    1411             :             "                               WARNING: The owner of the keys to 'owneraddress' will be the only one allowed to spend these coins.\n"
    1412             :             "5. \"include_delegated\" (boolean, optional, default = false) include already delegated inputs if needed.\n"
    1413             :             "6. \"from_shield\"       (boolean, optional, default = false) delegate shield funds.\n"
    1414             :             "7. \"force\"             (boolean, optional, default = false) ONLY FOR TESTING: force the creation even if SPORK 17 is disabled (for tests).\n"
    1415             : 
    1416             :             "\nResult:\n"
    1417             :             "\"transaction\"            (string) hex string of the transaction\n"
    1418             : 
    1419           0 :             "\nExamples:\n" +
    1420           0 :             HelpExampleCli("rawdelegatestake", "\"S1t2a3kab9c8c71VA78xxxy4MxZg6vgeS6\" 100") +
    1421           0 :             HelpExampleCli("rawdelegatestake", "\"S1t2a3kab9c8c71VA78xxxy4MxZg6vgeS6\" 1000 \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg34fk\"") +
    1422           0 :             HelpExampleRpc("rawdelegatestake", "\"S1t2a3kab9c8c71VA78xxxy4MxZg6vgeS6\", 1000, \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg34fk\""));
    1423             : 
    1424           2 :     EnsureWalletIsUnlocked(pwallet);
    1425             : 
    1426             :     // Make sure the results are valid at least up to the most recent block
    1427             :     // the user could have gotten from another RPC command prior to now
    1428           2 :     pwallet->BlockUntilSyncedToCurrentChain();
    1429             : 
    1430           6 :     LOCK2(cs_main, pwallet->cs_wallet);
    1431             : 
    1432           2 :     CTransactionRef wtx;
    1433           4 :     CReserveKey reservekey(pwallet);
    1434           2 :     CreateColdStakeDelegation(pwallet, request.params, wtx, reservekey);
    1435             : 
    1436           4 :     return EncodeHexTx(*wtx);
    1437             : }
    1438             : 
    1439             : 
    1440          49 : static CAmount getBalanceShieldedAddr(CWallet* const pwallet, Optional<libzcash::SaplingPaymentAddress>& filterAddress, int minDepth = 1, bool ignoreUnspendable=true) {
    1441          49 :     CAmount balance = 0;
    1442          49 :     std::vector<SaplingNoteEntry> saplingEntries;
    1443         147 :     LOCK2(cs_main, pwallet->cs_wallet);
    1444          49 :     pwallet->GetSaplingScriptPubKeyMan()->GetFilteredNotes(saplingEntries, filterAddress, minDepth, true, ignoreUnspendable);
    1445         121 :     for (auto & entry : saplingEntries) {
    1446          72 :         balance += CAmount(entry.note.value());
    1447             :     }
    1448          98 :     return balance;
    1449             : }
    1450             : 
    1451          54 : UniValue getshieldbalance(const JSONRPCRequest& request)
    1452             : {
    1453          54 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1454             : 
    1455          54 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1456           0 :         return NullUniValue;
    1457             : 
    1458          54 :     if (request.fHelp || request.params.size() > 3)
    1459           0 :         throw std::runtime_error(
    1460             :                 "getshieldbalance \"address\" ( minconf include_watchonly )\n"
    1461             :                 "\nReturn the total shield value of funds stored in the node's wallet or if an address was given,"
    1462             :                 "\nreturns the balance of the shield addr belonging to the node's wallet.\n"
    1463             :                 "\nCAUTION: If the wallet contains any addresses for which it only has incoming viewing keys,"
    1464             :                 "\nthe returned private balance may be larger than the actual balance, because spends cannot"
    1465             :                 "\nbe detected with incoming viewing keys.\n"
    1466             : 
    1467             :                 "\nArguments:\n"
    1468             :                 "1. \"address\"        (string, optional) The selected address. If non empty nor \"*\", it must be a Sapling address\n"
    1469             :                 "2. minconf            (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
    1470             :                 "3. include_watchonly  (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'importsaplingviewingkey')\n"
    1471             : 
    1472             :                 "\nResult:\n"
    1473             :                 "amount              (numeric) the total balance of shield funds (in Sapling addresses)\n"
    1474             : 
    1475             :                 "\nExamples:\n"
    1476             :                 "\nThe total amount in the wallet\n"
    1477           0 :                 + HelpExampleCli("getshieldbalance", "")
    1478           0 :                 + HelpExampleCli("getshieldbalance", "ptestsapling1h0w73csah2aq0a32h42kr7tq4htlt5wfn4ejxfnm56f6ehjvek7k4e244g6v8v3pgylmz5ea8jh") +
    1479             :                 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
    1480           0 :                 + HelpExampleCli("getshieldbalance", "\"*\" \"5\"") +
    1481             :                 "\nAs a json rpc call\n"
    1482           0 :                 + HelpExampleRpc("getshieldbalance", "\"*\" \"5\"")
    1483           0 :         );
    1484             : 
    1485         157 :     LOCK2(cs_main, pwallet->cs_wallet);
    1486             : 
    1487         108 :     Optional<libzcash::SaplingPaymentAddress> address;
    1488          54 :     if (request.params.size() > 0) {
    1489          94 :         std::string addressStr = request.params[0].get_str();
    1490          94 :         if (addressStr.empty() || addressStr != "*") {
    1491          84 :             address = KeyIO::DecodeSaplingPaymentAddress(addressStr);
    1492          42 :             if (!address) {
    1493           6 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid shield address");
    1494             :             }
    1495             :         }
    1496             :     }
    1497             : 
    1498          51 :     const int nMinDepth = request.params.size() > 1 ? request.params[1].get_int() : 1;
    1499           9 :     if (nMinDepth < 0) {
    1500           4 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
    1501             :     }
    1502             : 
    1503          49 :     const bool fIncludeWatchonly = request.params.size() > 2 && request.params[2].get_bool();
    1504          49 :     CAmount nBalance = getBalanceShieldedAddr(pwallet, address, nMinDepth, !fIncludeWatchonly);
    1505          49 :     return ValueFromAmount(nBalance);
    1506             : }
    1507             : 
    1508          11 : UniValue viewshieldtransaction(const JSONRPCRequest& request)
    1509             : {
    1510          11 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1511             : 
    1512          11 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1513           0 :         return NullUniValue;
    1514             : 
    1515          11 :     if (request.fHelp || request.params.size() != 1)
    1516           0 :         throw std::runtime_error(
    1517             :                 "viewshieldtransaction \"txid\"\n"
    1518             :                 "\nGet detailed shield information about in-wallet transaction \"txid\"\n"
    1519           0 :                 + HelpRequiringPassphrase(pwallet) + "\n"
    1520             : 
    1521             :                 "\nArguments:\n"
    1522             :                 "1. \"txid\"    (string, required) The transaction id\n"
    1523             :                 "\nResult:\n"
    1524             :                 "{\n"
    1525             :                 "  \"txid\" : \"transactionid\",   (string) The transaction id\n"
    1526           0 :                 "  \"fee\"  : x.xxx,               (numeric) The transaction fee in " + CURRENCY_UNIT + "\n"
    1527             :                 "  \"spends\" : [\n"
    1528             :                 "    {\n"
    1529             :                 "      \"spend\" : n,                    (numeric, sapling) the index of the spend within vShieldedSpend\n"
    1530             :                 "      \"txidPrev\" : \"transactionid\",   (string) The id for the transaction this note was created in\n"
    1531             :                 "      \"outputPrev\" : n,               (numeric, sapling) the index of the output within the vShieldedOutput\n"
    1532             :                 "      \"address\" : \"pivxaddress\",     (string) The PIVX address involved in the transaction\n"
    1533           0 :                 "      \"value\" : x.xxx                 (numeric) The amount in " + CURRENCY_UNIT + "\n"
    1534             :                 "      \"valueSat\" : xxxx               (numeric) The amount in satoshis\n"
    1535             :                 "    }\n"
    1536             :                 "    ,...\n"
    1537             :                 "  ],\n"
    1538             :                 "  \"outputs\" : [\n"
    1539             :                 "    {\n"
    1540             :                 "      \"output\" : n,                   (numeric, sapling) the index of the output within the vShieldedOutput\n"
    1541             :                 "      \"address\" : \"pivxaddress\",     (string) The PIVX address involved in the transaction\n"
    1542             :                 "      \"outgoing\" : true|false         (boolean, sapling) True if the output is not for an address in the wallet\n"
    1543           0 :                 "      \"value\" : x.xxx                 (numeric) The amount in " + CURRENCY_UNIT + "\n"
    1544             :                 "      \"valueSat\" : xxxx               (numeric) The amount in satoshis\n"
    1545             :                 "      \"memo\" : \"hexmemo\",             (string) Hexadecimal string representation of the memo field\n"
    1546             :                 "      \"memoStr\" : \"memo\",             (string) Only returned if memo contains valid UTF-8 text.\n"
    1547             :                 "    }\n"
    1548             :                 "    ,...\n"
    1549             :                 "  ],\n"
    1550             :                 "}\n"
    1551             : 
    1552             :                 "\nExamples:\n"
    1553           0 :                 + HelpExampleCli("viewshieldtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    1554           0 :                 + HelpExampleRpc("viewshieldtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    1555           0 :         );
    1556             : 
    1557          11 :     if (!pwallet->HasSaplingSPKM()) {
    1558           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Sapling wallet not initialized.");
    1559             :     }
    1560             : 
    1561          11 :     EnsureWalletIsUnlocked(pwallet);
    1562             : 
    1563             :     // Make sure the results are valid at least up to the most recent block
    1564             :     // the user could have gotten from another RPC command prior to now
    1565          11 :     pwallet->BlockUntilSyncedToCurrentChain();
    1566             : 
    1567          33 :     LOCK2(cs_main, pwallet->cs_wallet);
    1568             : 
    1569          11 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    1570             : 
    1571          22 :     UniValue entry(UniValue::VOBJ);
    1572          11 :     auto it = pwallet->mapWallet.find(hash);
    1573          11 :     if (it == pwallet->mapWallet.end())
    1574           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
    1575          11 :     const CWalletTx& wtx = it->second;
    1576             : 
    1577          11 :     if (!wtx.tx->IsShieldedTx()) {
    1578           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid transaction, no shield data available");
    1579             :     }
    1580             : 
    1581          22 :     entry.pushKV("txid", hash.GetHex());
    1582             : 
    1583          22 :     UniValue spends(UniValue::VARR);
    1584          11 :     UniValue outputs(UniValue::VARR);
    1585             : 
    1586          29 :     auto addMemo = [](UniValue& entry, const Optional<std::array<unsigned char, ZC_MEMO_SIZE>>& optMemo) {
    1587             :         // empty memo
    1588          18 :         if (!static_cast<bool>(optMemo)) {
    1589          15 :             const std::array<unsigned char, 1> memo {0xF6};
    1590          30 :             entry.pushKV("memo", HexStr(memo));
    1591          15 :             return;
    1592             :         }
    1593           3 :         const auto& memo = *optMemo;
    1594           3 :         auto end = FindFirstNonZero(memo.rbegin(), memo.rend());
    1595           9 :         entry.pushKV("memo", HexStr(std::vector<unsigned char>(memo.begin(), end.base())));
    1596             :         // If the leading byte is 0xF4 or lower, the memo field should be interpreted as a
    1597             :         // UTF-8-encoded text string.
    1598           3 :         if (memo[0] <= 0xf4) {
    1599           6 :             std::string memoStr(memo.begin(), end.base());
    1600           3 :             if (IsValidUTF8(memoStr)) {
    1601           6 :                 entry.pushKV("memoStr", memoStr);
    1602             :             }
    1603             :         }
    1604             :     };
    1605             : 
    1606          11 :     auto sspkm = pwallet->GetSaplingScriptPubKeyMan();
    1607             : 
    1608             :     // Collect OutgoingViewingKeys for recovering output information
    1609          22 :     std::set<uint256> ovks;
    1610             :     // Get the common OVK for recovering t->shield outputs.
    1611             :     // If not already databased, a new one will be generated from the HD seed.
    1612             :     // It is safe to do it here, as the wallet is unlocked.
    1613          11 :     ovks.insert(sspkm->getCommonOVK());
    1614             : 
    1615             :     // Sapling spends
    1616          20 :     for (size_t i = 0; i < wtx.tx->sapData->vShieldedSpend.size(); ++i) {
    1617           9 :         const auto& spend = wtx.tx->sapData->vShieldedSpend[i];
    1618             : 
    1619             :         // Fetch the note that is being spent
    1620           9 :         auto res = sspkm->mapSaplingNullifiersToNotes.find(spend.nullifier);
    1621           9 :         if (res == sspkm->mapSaplingNullifiersToNotes.end()) {
    1622           0 :             continue;
    1623             :         }
    1624           9 :         const auto& op = res->second;
    1625          18 :         std::string addrStr = "unknown";
    1626          18 :         UniValue amountStr = UniValue("unknown");
    1627           9 :         CAmount amount = 0;
    1628           9 :         auto wtxPrevIt = pwallet->mapWallet.find(op.hash);
    1629           9 :         if (wtxPrevIt != pwallet->mapWallet.end()) {
    1630           9 :             const auto ndIt = wtxPrevIt->second.mapSaplingNoteData.find(op);
    1631           9 :             if (ndIt != wtxPrevIt->second.mapSaplingNoteData.end()) {
    1632             :                 // get cached address and amount
    1633           9 :                 if (ndIt->second.address) {
    1634           9 :                     addrStr = KeyIO::EncodePaymentAddress(*(ndIt->second.address));
    1635             :                 }
    1636           9 :                 if (ndIt->second.amount) {
    1637           9 :                     amount = *(ndIt->second.amount);
    1638           9 :                     amountStr = ValueFromAmount(amount);
    1639             :                 }
    1640             :             }
    1641             :         }
    1642             : 
    1643          18 :         UniValue entry_(UniValue::VOBJ);
    1644           9 :         entry_.pushKV("spend", (int)i);
    1645          18 :         entry_.pushKV("txidPrev", op.hash.GetHex());
    1646           9 :         entry_.pushKV("outputPrev", (int)op.n);
    1647           9 :         entry_.pushKV("address", addrStr);
    1648           9 :         entry_.pushKV("value", amountStr);
    1649           9 :         entry_.pushKV("valueSat", amount);
    1650           9 :         spends.push_back(entry_);
    1651             :     }
    1652             : 
    1653             :     // Sapling outputs
    1654          29 :     for (uint32_t i = 0; i < wtx.tx->sapData->vShieldedOutput.size(); ++i) {
    1655          18 :         auto op = SaplingOutPoint(hash, i);
    1656          18 :         auto it = wtx.mapSaplingNoteData.find(op);
    1657          18 :         if (it == wtx.mapSaplingNoteData.end()) continue;
    1658          18 :         const auto& nd = it->second;
    1659             : 
    1660          18 :         const bool isOutgoing = !nd.IsMyNote();
    1661          36 :         std::string addrStr = "unknown";
    1662          36 :         UniValue amountStr = UniValue("unknown");
    1663          18 :         CAmount amount = 0;
    1664          18 :         if (nd.address) {
    1665          18 :             addrStr = KeyIO::EncodePaymentAddress(*(nd.address));
    1666             :         }
    1667          18 :         if (nd.amount) {
    1668          18 :             amount = *(nd.amount);
    1669          18 :             amountStr = ValueFromAmount(amount);
    1670             :         }
    1671             : 
    1672          36 :         UniValue entry_(UniValue::VOBJ);
    1673          18 :         entry_.pushKV("output", (int)op.n);
    1674          18 :         entry_.pushKV("outgoing", isOutgoing);
    1675          18 :         entry_.pushKV("address", addrStr);
    1676          18 :         entry_.pushKV("value", amountStr);
    1677          18 :         entry_.pushKV("valueSat", amount);
    1678          18 :         addMemo(entry_, nd.memo);
    1679             : 
    1680          18 :         outputs.push_back(entry_);
    1681             :     }
    1682             : 
    1683          22 :     entry.pushKV("fee", FormatMoney(pcoinsTip->GetValueIn(*wtx.tx) - wtx.tx->GetValueOut()));
    1684          11 :     entry.pushKV("spends", spends);
    1685          11 :     entry.pushKV("outputs", outputs);
    1686             : 
    1687          11 :     return entry;
    1688             : }
    1689             : 
    1690          91 : static SaplingOperation CreateShieldedTransaction(CWallet* const pwallet, const JSONRPCRequest& request)
    1691             : {
    1692         182 :     LOCK2(cs_main, pwallet->cs_wallet);
    1693          91 :     SaplingOperation operation(Params().GetConsensus(), pwallet);
    1694             : 
    1695             :     // Param 0: source of funds. Can either be a valid address, sapling address,
    1696             :     // or the string "from_transparent"|"from_trans_cold"|"from_shield"
    1697          91 :     bool fromSapling  = false;
    1698         182 :     std::string sendFromStr = request.params[0].get_str();
    1699          91 :     if (sendFromStr == "from_transparent") {
    1700             :         // send from any transparent address
    1701          35 :         operation.setSelectTransparentCoins(true);
    1702          56 :     } else if (sendFromStr == "from_trans_cold") {
    1703             :         // send from any transparent address + delegations
    1704           0 :         operation.setSelectTransparentCoins(true, true);
    1705          56 :     } else if (sendFromStr == "from_shield") {
    1706             :         // send from any shield address
    1707          15 :         operation.setSelectShieldedCoins(true);
    1708          15 :         fromSapling = true;
    1709             :     } else {
    1710          82 :         CTxDestination fromTAddressDest = DecodeDestination(sendFromStr);
    1711          41 :         if (!IsValidDestination(fromTAddressDest)) {
    1712          54 :             auto res = KeyIO::DecodePaymentAddress(sendFromStr);
    1713          27 :             if (!IsValidPaymentAddress(res)) {
    1714           2 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or shield addr.");
    1715             :             }
    1716          26 :             libzcash::SaplingPaymentAddress fromShieldedAddress = *boost::get<libzcash::SaplingPaymentAddress>(&res);
    1717          26 :             if (!pwallet->HaveSpendingKeyForPaymentAddress(fromShieldedAddress)) {
    1718           2 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, shield addr spending key not found.");
    1719             :             }
    1720             :             // send from user-supplied shield address
    1721          25 :             operation.setFromAddress(fromShieldedAddress);
    1722          25 :             fromSapling = true;
    1723             :         } else {
    1724             :             // send from user-supplied transparent address
    1725          14 :             operation.setFromAddress(fromTAddressDest);
    1726             :         }
    1727             :     }
    1728             : 
    1729             :     // Param 4: subtractFeeFromAmount addresses
    1730         178 :     const UniValue subtractFeeFromAmount = request.params[4];
    1731             : 
    1732             :     // Param 1: array of outputs
    1733          95 :     UniValue outputs = request.params[1].get_array();
    1734          89 :     if (outputs.empty())
    1735           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
    1736             : 
    1737             :     // Keep track of addresses to spot duplicates
    1738         176 :     std::set<std::string> setAddress;
    1739             :     // Recipients
    1740         176 :     std::vector<SendManyRecipient> recipients;
    1741          88 :     CAmount nTotalOut = 0;
    1742          88 :     bool containsSaplingOutput = false;
    1743             : 
    1744         247 :     for (const UniValue& o : outputs.getValues()) {
    1745         159 :         if (!o.isObject())
    1746           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
    1747             : 
    1748             :         // sanity check, report error if unknown key-value pairs
    1749         481 :         for (const std::string& name_ : o.getKeys()) {
    1750         489 :             if (name_ != "address" && name_ != "amount" && name_!="memo")
    1751           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, unknown key: ")+name_);
    1752             :         }
    1753             : 
    1754         477 :         std::string address = find_value(o, "address").get_str();
    1755         318 :         CTxDestination taddr = DecodeDestination(address);
    1756         318 :         Optional<libzcash::SaplingPaymentAddress> saddr;
    1757             : 
    1758         159 :         if (!IsValidDestination(taddr)) {
    1759         270 :             const auto& addr = KeyIO::DecodePaymentAddress(address);
    1760         135 :             if (IsValidPaymentAddress(addr)) {
    1761         135 :                 saddr = *(boost::get<libzcash::SaplingPaymentAddress>(&addr));
    1762         135 :                 containsSaplingOutput = true;
    1763             :             } else {
    1764           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, unknown address format: ")+address );
    1765             :             }
    1766             :         }
    1767             : 
    1768         159 :         if (setAddress.count(address))
    1769           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+address);
    1770         159 :         setAddress.insert(address);
    1771             : 
    1772         318 :         UniValue memoValue = find_value(o, "memo");
    1773         318 :         std::string memo;
    1774         159 :         if (!memoValue.isNull()) {
    1775           4 :             memo = memoValue.get_str();
    1776           4 :             if (!saddr) {
    1777           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a shield addr.");
    1778             :             }
    1779           4 :             if (memo.length() > ZC_MEMO_SIZE*2) {
    1780           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER,  strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
    1781             :             }
    1782             :         }
    1783             : 
    1784         318 :         UniValue av = find_value(o, "amount");
    1785         159 :         CAmount nAmount = AmountFromValue(av);
    1786         159 :         if (nAmount < 0)
    1787           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
    1788             : 
    1789         159 :         bool fSubtractFeeFromAmount = false;
    1790         161 :         for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
    1791           6 :             const UniValue& addr = subtractFeeFromAmount[idx];
    1792           6 :             if (addr.get_str() == address) {
    1793           4 :                 fSubtractFeeFromAmount = true;
    1794           4 :                 break;
    1795             :             }
    1796             :         }
    1797             : 
    1798         159 :         if (saddr) {
    1799         135 :             recipients.emplace_back(*saddr, nAmount, memo, fSubtractFeeFromAmount);
    1800             :         } else {
    1801          24 :             recipients.emplace_back(taddr, nAmount, fSubtractFeeFromAmount);
    1802             :         }
    1803             : 
    1804         159 :         nTotalOut += nAmount;
    1805             :     }
    1806             : 
    1807             :     // Check network status
    1808          88 :     if (sporkManager.IsSporkActive(SPORK_20_SAPLING_MAINTENANCE)) {
    1809             :         // If Sapling is disabled, do not allow sending from or sending to Sapling addresses.
    1810           1 :         if (fromSapling || containsSaplingOutput) {
    1811           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "SHIELD in maintenance (SPORK 20)");
    1812             :         }
    1813             :     }
    1814             : 
    1815             :     // Now check the transaction
    1816         174 :     auto opResult = CheckTransactionSize(recipients, !fromSapling);
    1817          87 :     if (!opResult) {
    1818           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, opResult.getError());
    1819             :     }
    1820             : 
    1821             :     // Param 2: Minimum confirmations
    1822          87 :     int nMinDepth = request.params.size() > 2 ? request.params[2].get_int() : 1;
    1823          75 :     if (nMinDepth < 0) {
    1824           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
    1825             :     }
    1826             : 
    1827             :     // Param 3: Fee
    1828             :     // If not set, SaplingOperation will set the minimum fee (based on minRelayFee and tx size)
    1829          87 :     if (request.params.size() > 3) {
    1830          54 :         CAmount nFee = AmountFromValue(request.params[3]);
    1831          54 :         if (nFee < 0) {
    1832           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid fee. Must be positive.");
    1833          54 :         } else if (nFee > 0) {
    1834             :             // If the user-selected fee is not enough (or too much), the build operation will fail.
    1835          35 :             operation.setFee(nFee);
    1836             :         }
    1837             :         // If nFee=0 leave the default (build operation will compute the minimum fee)
    1838             :     }
    1839             : 
    1840          87 :     if (fromSapling && nMinDepth == 0) {
    1841           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be zero when sending from shield addr");
    1842             :     }
    1843             : 
    1844          87 :     if (nMinDepth < 0) {
    1845           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be negative");
    1846             :     }
    1847             : 
    1848             :     // Build the send operation
    1849          87 :     OperationResult res = operation.setMinDepth(nMinDepth)
    1850             :             ->setRecipients(recipients)
    1851         174 :             ->build();
    1852          91 :     if (!res) throw JSONRPCError(RPC_WALLET_ERROR, res.getError());
    1853         166 :     return operation;
    1854             : }
    1855             : 
    1856          55 : UniValue shieldsendmany(const JSONRPCRequest& request)
    1857             : {
    1858          55 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1859             : 
    1860          55 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1861           0 :         return NullUniValue;
    1862             : 
    1863          55 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
    1864           2 :         throw std::runtime_error(
    1865             :                 "shieldsendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf fee subtract_fee_from )\n"
    1866             :                 "\nSend to many recipients. Amounts are decimal numbers with at most 8 digits of precision."
    1867             :                 "\nChange generated from a transparent addr flows to a new  transparent addr address, while change generated from a shield addr returns to itself."
    1868             :                 "\nWhen sending coinbase UTXOs to a shield addr, change is not allowed. The entire value of the UTXO(s) must be consumed."
    1869           4 :                 + HelpRequiringPassphrase(pwallet) + "\n"
    1870             : 
    1871             :                 "\nArguments:\n"
    1872             :                 "1. \"fromaddress\"         (string, required) The transparent addr or shield addr to send the funds from.\n"
    1873             :                 "                             It can also be the string \"from_transparent\"|\"from_shield\" to send the funds\n"
    1874             :                 "                             from any transparent|shield address available.\n"
    1875             :                 "                             Additionally, it can be the string \"from_trans_cold\" to select transparent funds,\n"
    1876             :                 "                             possibly including delegated coins, if needed.\n"
    1877             :                 "2. \"amounts\"             (array, required) An array of json objects representing the amounts to send.\n"
    1878             :                 "    [{\n"
    1879             :                 "      \"address\":address  (string, required) The address is a transparent addr or shield addr\n"
    1880           4 :                 "      \"amount\":amount    (numeric, required) The numeric amount in " + "PIV" + " is the value\n"
    1881             :                 "      \"memo\":memo        (string, optional) If the address is a shield addr, message string of max 512 bytes\n"
    1882             :                 "    }, ... ]\n"
    1883             :                 "3. minconf               (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
    1884             :                 "4. fee                   (numeric, optional), The fee amount to attach to this transaction.\n"
    1885             :                 "                            If not specified, or set to 0, the wallet will try to compute the minimum possible fee for a shield TX,\n"
    1886             :                 "                            based on the expected transaction size and the current value of -minRelayTxFee.\n"
    1887             :                 "5. subtract_fee_from     (array, optional) A json array with addresses.\n"
    1888             :                 "                           The fee will be equally deducted from the amount of each selected address.\n"
    1889             :                 "                           Those recipients will receive less PIV than you enter in their corresponding amount field.\n"
    1890             :                 "                           If no addresses are specified here, the sender pays the fee.\n"
    1891             :                 "    [\n"
    1892             :                 "      \"address\"          (string) Subtract fee from this address\n"
    1893             :                 "      ,...\n"
    1894             :                 "    ]\n"
    1895             :                 "\nResult:\n"
    1896             :                 "\"id\"          (string) transaction hash in the network\n"
    1897             :                 "\nExamples:\n"
    1898          10 :                 + HelpExampleCli("shieldsendmany",
    1899             :                                  "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" '[{\"address\": \"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\" ,\"amount\": 5.0}]'")
    1900           8 :                 + HelpExampleRpc("shieldsendmany",
    1901             :                                  "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\", [{\"address\": \"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\" ,\"amount\": 5.0}]")
    1902           6 :         );
    1903             : 
    1904          53 :     EnsureWalletIsUnlocked(pwallet);
    1905             : 
    1906             :     // Make sure the results are valid at least up to the most recent block
    1907             :     // the user could have gotten from another RPC command prior to now
    1908          53 :     pwallet->BlockUntilSyncedToCurrentChain();
    1909             : 
    1910          54 :     SaplingOperation operation = CreateShieldedTransaction(pwallet, request);
    1911          94 :     std::string txHash;
    1912          94 :     auto res = operation.send(txHash);
    1913          47 :     if (!res)
    1914           2 :         throw JSONRPCError(RPC_WALLET_ERROR, res.getError());
    1915          46 :     return txHash;
    1916             : }
    1917             : 
    1918          21 : UniValue rawshieldsendmany(const JSONRPCRequest& request)
    1919             : {
    1920          21 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1921             : 
    1922          21 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1923           0 :         return NullUniValue;
    1924             : 
    1925          21 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
    1926           0 :         throw std::runtime_error(
    1927             :                 "rawshieldsendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf fee )\n"
    1928             :                 "\nCreates a transaction sending to many recipients (without committing it), and returns the hex string."
    1929             :                 "\nAmounts are decimal numbers with at most 8 digits of precision."
    1930             :                 "\nChange generated from a transparent addr flows to a new  transparent addr address, while change generated from a shield addr returns to itself."
    1931             :                 "\nWhen sending coinbase UTXOs to a shield addr, change is not allowed. The entire value of the UTXO(s) must be consumed."
    1932           0 :                 + HelpRequiringPassphrase(pwallet) + "\n"
    1933             : 
    1934             :                 "\nArguments:\n"
    1935             :                 "1. \"fromaddress\"         (string, required) The transparent addr or shield addr to send the funds from.\n"
    1936             :                 "                             It can also be the string \"from_transparent\"|\"from_shield\" to send the funds\n"
    1937             :                 "                             from any transparent|shield address available.\n"
    1938             :                 "                             Additionally, it can be the string \"from_trans_cold\" to select transparent funds,\n"
    1939             :                 "                             possibly including delegated coins, if needed.\n"
    1940             :                 "2. \"amounts\"             (array, required) An array of json objects representing the amounts to send.\n"
    1941             :                 "    [{\n"
    1942             :                 "      \"address\":address  (string, required) The address is a transparent addr or shield addr\n"
    1943           0 :                 "      \"amount\":amount    (numeric, required) The numeric amount in " + "PIV" + " is the value\n"
    1944             :                 "      \"memo\":memo        (string, optional) If the address is a shield addr, message string of max 512 bytes\n"
    1945             :                 "    }, ... ]\n"
    1946             :                 "3. minconf               (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
    1947             :                 "4. fee                   (numeric, optional), The fee amount to attach to this transaction.\n"
    1948             :                 "                            If not specified, the wallet will try to compute the minimum possible fee for a shield TX,\n"
    1949             :                 "                            based on the expected transaction size and the current value of -minRelayTxFee.\n"
    1950             :                 "\nResult:\n"
    1951             :                 "\"transaction\"            (string) hex string of the transaction\n"
    1952             : 
    1953             :                 "\nExamples:\n"
    1954           0 :                 + HelpExampleCli("rawshieldsendmany",
    1955             :                                  "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" '[{\"address\": \"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\" ,\"amount\": 5.0}]'")
    1956           0 :                 + HelpExampleRpc("rawshieldsendmany",
    1957             :                                  "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\", [{\"address\": \"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\" ,\"amount\": 5.0}]")
    1958           0 :         );
    1959             : 
    1960          21 :     EnsureWalletIsUnlocked(pwallet);
    1961             : 
    1962             :     // Make sure the results are valid at least up to the most recent block
    1963             :     // the user could have gotten from another RPC command prior to now
    1964          21 :     pwallet->BlockUntilSyncedToCurrentChain();
    1965             : 
    1966          40 :     CTransaction tx = CreateShieldedTransaction(pwallet, request).getFinalTx();
    1967          38 :     return EncodeHexTx(tx);
    1968             : }
    1969             : 
    1970           1 : UniValue listaddressgroupings(const JSONRPCRequest& request)
    1971             : {
    1972           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1973             : 
    1974           1 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1975           0 :         return NullUniValue;
    1976             : 
    1977           1 :     if (request.fHelp || !request.params.empty())
    1978           0 :         throw std::runtime_error(
    1979             :             "listaddressgroupings\n"
    1980             :             "\nLists groups of addresses which have had their common ownership\n"
    1981             :             "made public by common use as inputs or as the resulting change\n"
    1982             :             "in past transactions\n"
    1983             : 
    1984             :             "\nResult:\n"
    1985             :             "[\n"
    1986             :             "  [\n"
    1987             :             "    [\n"
    1988             :             "      \"pivxaddress\",     (string) The pivx address\n"
    1989             :             "      amount,                 (numeric) The amount in PIV\n"
    1990             :             "      \"label\"             (string, optional) The label\n"
    1991             :             "    ]\n"
    1992             :             "    ,...\n"
    1993             :             "  ]\n"
    1994             :             "  ,...\n"
    1995             :             "]\n"
    1996             : 
    1997           0 :             "\nExamples:\n" +
    1998           0 :             HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", ""));
    1999             : 
    2000             :     // Make sure the results are valid at least up to the most recent block
    2001             :     // the user could have gotten from another RPC command prior to now
    2002           1 :     pwallet->BlockUntilSyncedToCurrentChain();
    2003             : 
    2004           3 :     LOCK2(cs_main, pwallet->cs_wallet);
    2005             : 
    2006           2 :     UniValue jsonGroupings(UniValue::VARR);
    2007           2 :     std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
    2008           3 :     for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {
    2009           4 :         UniValue jsonGrouping(UniValue::VARR);
    2010           4 :         for (CTxDestination address : grouping) {
    2011           4 :             UniValue addressInfo(UniValue::VARR);
    2012           2 :             addressInfo.push_back(EncodeDestination(address));
    2013           2 :             addressInfo.push_back(ValueFromAmount(balances[address]));
    2014           4 :             auto optAdd = pwallet->GetAddressBookEntry(address);
    2015           2 :             if (optAdd) {
    2016           0 :                 addressInfo.push_back(optAdd->name);
    2017             :             }
    2018           2 :             jsonGrouping.push_back(addressInfo);
    2019             :         }
    2020           2 :         jsonGroupings.push_back(jsonGrouping);
    2021             :     }
    2022           1 :     return jsonGroupings;
    2023             : }
    2024             : 
    2025           5 : UniValue signmessage(const JSONRPCRequest& request)
    2026             : {
    2027           5 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2028             : 
    2029           5 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2030           0 :         return NullUniValue;
    2031             : 
    2032           5 :     if (request.fHelp || request.params.size() != 2)
    2033           0 :         throw std::runtime_error(
    2034             :             "signmessage \"address\" \"message\"\n"
    2035           0 :             "\nSign a message with the private key of an address" +
    2036           0 :             HelpRequiringPassphrase(pwallet) + "\n"
    2037             : 
    2038             :             "\nArguments:\n"
    2039             :             "1. \"address\"     (string, required) The pivx address to use for the private key.\n"
    2040             :             "2. \"message\"     (string, required) The message to create a signature of.\n"
    2041             : 
    2042             :             "\nResult:\n"
    2043             :             "\"signature\"          (string) The signature of the message encoded in base 64\n"
    2044             : 
    2045             :             "\nExamples:\n"
    2046           0 :             "\nUnlock the wallet for 30 seconds\n" +
    2047           0 :             HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
    2048           0 :             "\nCreate the signature\n" +
    2049           0 :             HelpExampleCli("signmessage", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" \"my message\"") +
    2050           0 :             "\nVerify the signature\n" +
    2051           0 :             HelpExampleCli("verifymessage", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" \"signature\" \"my message\"") +
    2052           0 :             "\nAs json rpc\n" +
    2053           0 :             HelpExampleRpc("signmessage", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\", \"my message\""));
    2054             : 
    2055          15 :     LOCK2(cs_main, pwallet->cs_wallet);
    2056             : 
    2057           5 :     EnsureWalletIsUnlocked(pwallet);
    2058             : 
    2059          10 :     std::string strAddress = request.params[0].get_str();
    2060          10 :     std::string strMessage = request.params[1].get_str();
    2061             : 
    2062          10 :     CTxDestination dest = DecodeDestination(strAddress);
    2063           5 :     if (!IsValidDestination(dest))
    2064           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
    2065             : 
    2066           5 :     const CKeyID* keyID = boost::get<CKeyID>(&dest);
    2067           5 :     if (!keyID)
    2068           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
    2069             : 
    2070          10 :     CKey key;
    2071           5 :     if (!pwallet->GetKey(*keyID, key))
    2072           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
    2073             : 
    2074          10 :     std::vector<unsigned char> vchSig;
    2075           5 :     if (!CMessageSigner::SignMessage(strMessage, vchSig, key)) {
    2076           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
    2077             :     }
    2078             : 
    2079          10 :     return EncodeBase64(vchSig);
    2080             : }
    2081             : 
    2082          16 : UniValue getreceivedbyaddress(const JSONRPCRequest& request)
    2083             : {
    2084          16 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2085             : 
    2086          16 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2087           0 :         return NullUniValue;
    2088             : 
    2089          16 :     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
    2090           0 :         throw std::runtime_error(
    2091             :             "getreceivedbyaddress \"address\" ( minconf )\n"
    2092             :             "\nReturns the total amount received by the given pivxaddress in transactions with at least minconf confirmations.\n"
    2093             : 
    2094             :             "\nArguments:\n"
    2095             :             "1. \"address\"    (string, required) The pivx address for transactions.\n"
    2096             :             "2. minconf        (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
    2097             : 
    2098             :             "\nResult:\n"
    2099             :             "amount   (numeric) The total amount in PIV received at this address.\n"
    2100             : 
    2101             :             "\nExamples:\n"
    2102           0 :             "\nThe amount from transactions with at least 1 confirmation\n" +
    2103           0 :             HelpExampleCli("getreceivedbyaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\"") +
    2104           0 :             "\nThe amount including unconfirmed transactions, zero confirmations\n" +
    2105           0 :             HelpExampleCli("getreceivedbyaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" 0") +
    2106           0 :             "\nThe amount with at least 6 confirmation, very safe\n" +
    2107           0 :             HelpExampleCli("getreceivedbyaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" 6") +
    2108           0 :             "\nAs a json rpc call\n" +
    2109           0 :             HelpExampleRpc("getreceivedbyaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\", 6"));
    2110             : 
    2111             :     // Make sure the results are valid at least up to the most recent block
    2112             :     // the user could have gotten from another RPC command prior to now
    2113          16 :     pwallet->BlockUntilSyncedToCurrentChain();
    2114             : 
    2115          47 :     LOCK2(cs_main, pwallet->cs_wallet);
    2116          16 :     int nBlockHeight = chainActive.Height();
    2117             : 
    2118             :     // pivx address
    2119          32 :     CTxDestination address = DecodeDestination(request.params[0].get_str());
    2120          16 :     if (!IsValidDestination(address))
    2121           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
    2122          32 :     CScript scriptPubKey = GetScriptForDestination(address);
    2123          16 :     if (!IsMine(*pwallet, scriptPubKey))
    2124           2 :         throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
    2125             : 
    2126             :     // Minimum confirmations
    2127          15 :     int nMinDepth = 1;
    2128          15 :     if (request.params.size() > 1)
    2129           1 :         nMinDepth = request.params[1].get_int();
    2130             : 
    2131             :     // Tally
    2132          15 :     CAmount nAmount = 0;
    2133        1027 :     for (const auto& entry : pwallet->mapWallet) {
    2134        1012 :         const CWalletTx& wtx = entry.second;
    2135        1012 :         if (wtx.IsCoinBase() || !IsFinalTx(wtx.tx, nBlockHeight))
    2136         960 :             continue;
    2137             : 
    2138         136 :         for (const CTxOut& txout : wtx.tx->vout)
    2139          84 :             if (txout.scriptPubKey == scriptPubKey)
    2140          11 :                 if (wtx.GetDepthInMainChain() >= nMinDepth)
    2141          10 :                     nAmount += txout.nValue;
    2142             :     }
    2143             : 
    2144          15 :     return ValueFromAmount(nAmount);
    2145             : }
    2146             : 
    2147             : 
    2148          14 : UniValue getreceivedbylabel(const JSONRPCRequest& request)
    2149             : {
    2150          14 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2151             : 
    2152          14 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2153           0 :         return NullUniValue;
    2154             : 
    2155          14 :     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
    2156           0 :         throw std::runtime_error(
    2157             :             "getreceivedbylabel \"label\" ( minconf )\n"
    2158             :             "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n"
    2159             : 
    2160             :             "\nArguments:\n"
    2161             :             "1. \"label\"      (string, required) The selected label, may be the default label using \"\".\n"
    2162             :             "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
    2163             : 
    2164             :             "\nResult:\n"
    2165             :             "amount              (numeric) The total amount in PIV received for this label.\n"
    2166             : 
    2167             :             "\nExamples:\n"
    2168           0 :             "\nAmount received by the default label with at least 1 confirmation\n" +
    2169           0 :             HelpExampleCli("getreceivedbylabel", "\"\"") +
    2170           0 :             "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n" +
    2171           0 :             HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
    2172           0 :             "\nThe amount with at least 6 confirmation, very safe\n" +
    2173           0 :             HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
    2174           0 :             "\nAs a json rpc call\n" +
    2175           0 :             HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6"));
    2176             : 
    2177             :     // Make sure the results are valid at least up to the most recent block
    2178             :     // the user could have gotten from another RPC command prior to now
    2179          14 :     pwallet->BlockUntilSyncedToCurrentChain();
    2180             : 
    2181          42 :     LOCK2(cs_main, pwallet->cs_wallet);
    2182          14 :     int nBlockHeight = chainActive.Height();
    2183             : 
    2184             :     // Minimum confirmations
    2185          14 :     int nMinDepth = 1;
    2186          14 :     if (request.params.size() > 1)
    2187           0 :         nMinDepth = request.params[1].get_int();
    2188             : 
    2189             :     // Get the set of pub keys assigned to label
    2190          28 :     std::string label = LabelFromValue(request.params[0]);
    2191          28 :     std::set<CTxDestination> setAddress = pwallet->GetLabelAddresses(label);
    2192             : 
    2193             :     // Tally
    2194          14 :     CAmount nAmount = 0;
    2195        1459 :     for (const auto& entry : pwallet->mapWallet) {
    2196        1445 :         const CWalletTx& wtx = entry.second;
    2197        1445 :         if (wtx.IsCoinBase() || !IsFinalTx(wtx.tx, nBlockHeight))
    2198        1345 :             continue;
    2199             : 
    2200         300 :         for (const CTxOut& txout : wtx.tx->vout) {
    2201         400 :             CTxDestination address;
    2202         349 :             if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwallet, address) && setAddress.count(address))
    2203          26 :                 if (wtx.GetDepthInMainChain() >= nMinDepth)
    2204          25 :                     nAmount += txout.nValue;
    2205             :         }
    2206             :     }
    2207             : 
    2208          14 :     return (double)nAmount / (double)COIN;
    2209             : }
    2210             : 
    2211         137 : UniValue getbalance(const JSONRPCRequest& request)
    2212             : {
    2213         137 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2214             : 
    2215         137 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2216           0 :         return NullUniValue;
    2217             : 
    2218         137 :     if (request.fHelp || (request.params.size() > 4 ))
    2219           0 :         throw std::runtime_error(
    2220             :             "getbalance ( minconf include_watchonly include_delegated include_shield )\n"
    2221             :             "\nReturns the server's total available balance.\n"
    2222             :             "The available balance is what the wallet considers currently spendable, and is\n"
    2223             :             "thus affected by options which limit spendability such as -spendzeroconfchange.\n"
    2224             : 
    2225             :             "\nArguments:\n"
    2226             :             "1. minconf          (numeric, optional, default=0) Only include transactions confirmed at least this many times.\n"
    2227             :             "2. include_watchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
    2228             :             "3. include_delegated (bool, optional, default=true) Also include balance delegated to cold stakers\n"
    2229             :             "4. include_shield    (bool, optional, default=true) Also include shield balance\n"
    2230             : 
    2231             :             "\nResult:\n"
    2232             :             "amount              (numeric) The total amount in PIV received for this wallet.\n"
    2233             : 
    2234             :             "\nExamples:\n"
    2235           0 :             "\nThe total amount in the wallet\n" +
    2236           0 :             HelpExampleCli("getbalance", "") +
    2237           0 :             "\nThe total amount in the wallet, with at least 5 confirmations\n" +
    2238           0 :             HelpExampleCli("getbalance", "6") +
    2239           0 :             "\nAs a json rpc call\n" +
    2240           0 :             HelpExampleRpc("getbalance", "6"));
    2241             : 
    2242             :     // Make sure the results are valid at least up to the most recent block
    2243             :     // the user could have gotten from another RPC command prior to now
    2244         137 :     pwallet->BlockUntilSyncedToCurrentChain();
    2245             : 
    2246         411 :     LOCK2(cs_main, pwallet->cs_wallet);
    2247             : 
    2248         137 :     const int paramsSize = request.params.size();
    2249         137 :     const int nMinDepth = paramsSize > 0 ? request.params[0].get_int() : 0;
    2250         137 :     bool fIncludeWatchOnly = paramsSize > 1 && request.params[1].get_bool();
    2251         137 :     bool fIncludeDelegated = paramsSize <= 2 || request.params[2].get_bool();
    2252         137 :     bool fIncludeShielded = paramsSize <= 3 || request.params[3].get_bool();
    2253             : 
    2254         137 :     isminefilter filter = ISMINE_SPENDABLE | (fIncludeWatchOnly ?
    2255             :                                               (fIncludeShielded ? ISMINE_WATCH_ONLY_ALL : ISMINE_WATCH_ONLY) : ISMINE_NO);
    2256         137 :     filter |= fIncludeDelegated ? ISMINE_SPENDABLE_DELEGATED : ISMINE_NO;
    2257         137 :     filter |= fIncludeShielded ? ISMINE_SPENDABLE_SHIELDED : ISMINE_NO;
    2258         137 :     return ValueFromAmount(pwallet->GetAvailableBalance(filter, true, nMinDepth));
    2259             : }
    2260             : 
    2261           9 : UniValue getcoldstakingbalance(const JSONRPCRequest& request)
    2262             : {
    2263           9 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2264             : 
    2265           9 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2266           0 :         return NullUniValue;
    2267             : 
    2268           9 :     if (request.fHelp || (request.params.size() != 0))
    2269           0 :         throw std::runtime_error(
    2270             :             "getcoldstakingbalance\n"
    2271             :             "\nReturns the server's total available cold balance.\n"
    2272             : 
    2273             :             "\nResult:\n"
    2274             :             "amount              (numeric) The total amount in PIV received for this wallet in P2CS contracts.\n"
    2275             : 
    2276             :             "\nExamples:\n"
    2277           0 :             "\nThe total amount in the wallet\n" +
    2278           0 :             HelpExampleCli("getcoldstakingbalance", "") +
    2279           0 :             "\nAs a json rpc call\n" +
    2280           0 :             HelpExampleRpc("getcoldstakingbalance", "\"*\""));
    2281             : 
    2282             :     // Make sure the results are valid at least up to the most recent block
    2283             :     // the user could have gotten from another RPC command prior to now
    2284           9 :     pwallet->BlockUntilSyncedToCurrentChain();
    2285             : 
    2286          27 :     LOCK2(cs_main, pwallet->cs_wallet);
    2287             : 
    2288           9 :     return ValueFromAmount(pwallet->GetColdStakingBalance());
    2289             : }
    2290             : 
    2291           8 : UniValue getdelegatedbalance(const JSONRPCRequest& request)
    2292             : {
    2293           8 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2294             : 
    2295           8 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2296           0 :         return NullUniValue;
    2297             : 
    2298           8 :     if (request.fHelp || (request.params.size() != 0))
    2299           0 :         throw std::runtime_error(
    2300             :             "getdelegatedbalance\n"
    2301             :             "\nReturns the server's total available delegated balance (sum of all utxos delegated\n"
    2302             :             "to a cold staking address to stake on behalf of addresses of this wallet).\n"
    2303             : 
    2304             :             "\nResult:\n"
    2305             :             "amount              (numeric) The total amount in PIV received for this wallet in P2CS contracts.\n"
    2306             : 
    2307             :             "\nExamples:\n"
    2308           0 :             "\nThe total amount in the wallet\n" +
    2309           0 :             HelpExampleCli("getdelegatedbalance", "") +
    2310           0 :             "\nAs a json rpc call\n" +
    2311           0 :             HelpExampleRpc("getdelegatedbalance", "\"*\""));
    2312             : 
    2313             :     // Make sure the results are valid at least up to the most recent block
    2314             :     // the user could have gotten from another RPC command prior to now
    2315           8 :     pwallet->BlockUntilSyncedToCurrentChain();
    2316             : 
    2317          24 :     LOCK2(cs_main, pwallet->cs_wallet);
    2318             : 
    2319           8 :     return ValueFromAmount(pwallet->GetDelegatedBalance());
    2320             : }
    2321             : 
    2322           2 : UniValue getunconfirmedbalance(const JSONRPCRequest& request)
    2323             : {
    2324           2 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2325             : 
    2326           2 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2327           0 :         return NullUniValue;
    2328             : 
    2329           2 :     if (request.fHelp || request.params.size() > 0)
    2330           0 :         throw std::runtime_error(
    2331             :             "getunconfirmedbalance\n"
    2332           0 :             "Returns the server's total unconfirmed balance\n");
    2333             : 
    2334             :     // Make sure the results are valid at least up to the most recent block
    2335             :     // the user could have gotten from another RPC command prior to now
    2336           2 :     pwallet->BlockUntilSyncedToCurrentChain();
    2337             : 
    2338           6 :     LOCK2(cs_main, pwallet->cs_wallet);
    2339             : 
    2340           2 :     return ValueFromAmount(pwallet->GetUnconfirmedBalance());
    2341             : }
    2342             : 
    2343             : /*
    2344             :  * Only used for t->t transactions (via sendmany RPC)
    2345             :  */
    2346           6 : static UniValue legacy_sendmany(CWallet* const pwallet, const UniValue& sendTo, int nMinDepth, std::string comment, bool fIncludeDelegated, const UniValue& subtractFeeFromAmount)
    2347             : {
    2348          12 :     LOCK2(cs_main, pwallet->cs_wallet);
    2349             : 
    2350           6 :     if (!g_connman)
    2351           0 :         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
    2352             : 
    2353           6 :     isminefilter filter = ISMINE_SPENDABLE | (fIncludeDelegated ? ISMINE_SPENDABLE_DELEGATED : ISMINE_NO);
    2354             : 
    2355           6 :     CTransactionRef txNew;
    2356          12 :     std::set<CTxDestination> setAddress;
    2357          12 :     std::vector<CRecipient> vecSend;
    2358             : 
    2359           6 :     CAmount totalAmount = 0;
    2360           6 :     std::vector<std::string> keys = sendTo.getKeys();
    2361          21 :     for (const std::string& name_ : keys) {
    2362          15 :         bool isStaking = false;
    2363          15 :         bool isExchange = false;
    2364          30 :         CTxDestination dest = DecodeDestination(name_, isStaking, isExchange);
    2365          15 :         if (!IsValidDestination(dest) || isStaking)
    2366           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid PIVX address: ")+name_);
    2367             : 
    2368          15 :         if (setAddress.count(dest))
    2369           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
    2370          15 :         setAddress.insert(dest);
    2371             : 
    2372          30 :         CScript scriptPubKey = GetScriptForDestination(dest);
    2373          15 :         CAmount nAmount = AmountFromValue(sendTo[name_]);
    2374          15 :         totalAmount += nAmount;
    2375             : 
    2376          15 :         bool fSubtractFeeFromAmount = false;
    2377          15 :         for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
    2378           1 :             const UniValue& addr = subtractFeeFromAmount[idx];
    2379           1 :             if (addr.get_str() == name_) {
    2380           1 :                 fSubtractFeeFromAmount = true;
    2381           1 :                 break;
    2382             :             }
    2383             :         }
    2384             : 
    2385          15 :         vecSend.emplace_back(scriptPubKey, nAmount, fSubtractFeeFromAmount);
    2386             :     }
    2387             : 
    2388             :     // Check funds
    2389           6 :     if (totalAmount > pwallet->GetLegacyBalance(filter, nMinDepth)) {
    2390           0 :         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Wallet has insufficient funds");
    2391             :     }
    2392             : 
    2393             :     // Send
    2394          12 :     CReserveKey keyChange(pwallet);
    2395           6 :     CAmount nFeeRequired = 0;
    2396          12 :     std::string strFailReason;
    2397           6 :     int nChangePosInOut = -1;
    2398           6 :     bool fCreated = pwallet->CreateTransaction(vecSend, txNew, keyChange, nFeeRequired, nChangePosInOut, strFailReason,
    2399             :                                                nullptr,     // coinControl
    2400             :                                                true,        // sign
    2401             :                                                0,           // nFeePay
    2402             :                                                fIncludeDelegated,
    2403             :                                                nullptr, // fStakeDelegationVoided
    2404             :                                                0, // default extra size
    2405             :                                                nMinDepth);
    2406           6 :     if (!fCreated)
    2407           0 :         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
    2408          12 :     const CWallet::CommitResult& res = pwallet->CommitTransaction(txNew, keyChange, g_connman.get());
    2409           6 :     if (res.status != CWallet::CommitStatus::OK)
    2410           0 :         throw JSONRPCError(RPC_WALLET_ERROR, res.ToString());
    2411             : 
    2412             :     // Set comment
    2413           6 :     CWalletTx& wtx = pwallet->mapWallet.at(txNew->GetHash());
    2414           6 :     if (!comment.empty()) {
    2415           0 :         wtx.mapValue["comment"] = comment;
    2416             :     }
    2417             : 
    2418          18 :     return wtx.GetHash().GetHex();
    2419             : }
    2420             : 
    2421             : /*
    2422             :  * This function uses [legacy_sendmany] in the background.
    2423             :  * If any recipient is a shield address, instead it uses [shieldsendmany "from_transparent"].
    2424             :  */
    2425           8 : UniValue sendmany(const JSONRPCRequest& request)
    2426             : {
    2427           8 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2428             : 
    2429           8 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2430           0 :         return NullUniValue;
    2431             : 
    2432           8 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 6)
    2433           0 :         throw std::runtime_error(
    2434             :             "sendmany \"\" {\"address\":amount,...} ( minconf \"comment\" include_delegated )\n"
    2435             :             "\nSend to multiple destinations. Recipients are transparent or shield PIVX addresses.\n"
    2436             :             "\nAmounts are double-precision floating point numbers.\n"
    2437           0 :             + HelpRequiringPassphrase(pwallet) + "\n"
    2438             : 
    2439             :             "\nArguments:\n"
    2440             :             "1. \"dummy\"               (string, required) Must be set to \"\" for backwards compatibility.\n"
    2441             :             "2. \"amounts\"             (string, required) A json object with addresses and amounts\n"
    2442             :             "    {\n"
    2443             :             "      \"address\":amount   (numeric) The pivx address (either transparent or shield) is the key,\n"
    2444             :             "                                     the numeric amount in PIV is the value\n"
    2445             :             "      ,...\n"
    2446             :             "    }\n"
    2447             :             "3. minconf                 (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
    2448             :             "4. \"comment\"             (string, optional) A comment\n"
    2449             :             "5. include_delegated       (bool, optional, default=false) Also include balance delegated to cold stakers\n"
    2450             :             "6. subtract_fee_from       (array, optional) A json array with addresses.\n"
    2451             :             "                           The fee will be equally deducted from the amount of each selected address.\n"
    2452             :             "                           Those recipients will receive less PIV than you enter in their corresponding amount field.\n"
    2453             :             "                           If no addresses are specified here, the sender pays the fee.\n"
    2454             :             "    [\n"
    2455             :             "      \"address\"          (string) Subtract fee from this address\n"
    2456             :             "      ,...\n"
    2457             :             "    ]\n"
    2458             : 
    2459             :             "\nResult:\n"
    2460             :             "\"transactionid\"          (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
    2461             :             "                                    the number of addresses.\n"
    2462             : 
    2463             :             "\nExamples:\n"
    2464           0 :             "\nSend two amounts to two different addresses:\n" +
    2465           0 :             HelpExampleCli("sendmany", "\"\" \"{\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\":0.01,\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\":0.02}\"") +
    2466           0 :             "\nSend two amounts to two different addresses setting the confirmation and comment:\n" +
    2467           0 :             HelpExampleCli("sendmany", "\"\" \"{\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\":0.01,\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\":0.02}\" 6 \"testing\"") +
    2468           0 :             "\nSend to shield address:\n" +
    2469           0 :             HelpExampleCli("sendmany", "\"\" \"{\\\"ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej\\\":10}\"") +
    2470           0 :             "\nAs a json rpc call\n" +
    2471           0 :             HelpExampleRpc("sendmany", "\"\", \"{\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\":0.01,\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\":0.02}\", 6, \"testing\"")
    2472           0 :         );
    2473             : 
    2474           8 :     EnsureWalletIsUnlocked(pwallet);
    2475             : 
    2476             :     // Make sure the results are valid at least up to the most recent block
    2477             :     // the user could have gotten from another RPC command prior to now
    2478           8 :     pwallet->BlockUntilSyncedToCurrentChain();
    2479             : 
    2480             :     // Read Params
    2481           8 :     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
    2482           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
    2483             :     }
    2484           8 :     const UniValue sendTo = request.params[1].get_obj();
    2485           8 :     const int nMinDepth = request.params.size() > 2 ? request.params[2].get_int() : 1;
    2486           8 :     const std::string comment = (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty()) ?
    2487          16 :                         request.params[3].get_str() : "";
    2488           8 :     const bool fIncludeDelegated = (request.params.size() > 4 && request.params[4].get_bool());
    2489             : 
    2490          16 :     UniValue subtractFeeFromAmount(UniValue::VARR);
    2491           8 :     if (request.params.size() > 5 && !request.params[5].isNull())
    2492           2 :         subtractFeeFromAmount = request.params[5].get_array();
    2493             : 
    2494             :     // Check  if any recipient address is shield
    2495           8 :     bool fShieldSend = false;
    2496          23 :     for (const std::string& key : sendTo.getKeys()) {
    2497          17 :         bool isStaking = false, isExchange = false, isShielded = false;
    2498          17 :         Standard::DecodeDestination(key, isStaking, isExchange, isShielded);
    2499          17 :         if (isShielded) {
    2500           2 :             fShieldSend = true;
    2501           2 :             break;
    2502             :         }
    2503             :     }
    2504             : 
    2505           8 :     if (fShieldSend) {
    2506           4 :         return ShieldSendManyTo(pwallet, sendTo, comment, "", nMinDepth, fIncludeDelegated, subtractFeeFromAmount);
    2507             :     }
    2508             : 
    2509             :     // All recipients are transparent: use Legacy sendmany t->t
    2510          18 :     return legacy_sendmany(pwallet, sendTo, nMinDepth, comment, fIncludeDelegated, subtractFeeFromAmount);
    2511             : }
    2512             : 
    2513             : // Defined in rpc/misc.cpp
    2514             : extern CScript _createmultisig_redeemScript(CWallet* const pwallet, const UniValue& params);
    2515             : 
    2516          12 : UniValue addmultisigaddress(const JSONRPCRequest& request)
    2517             : {
    2518          12 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2519             : 
    2520          12 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2521           0 :         return NullUniValue;
    2522             : 
    2523          12 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
    2524           0 :         throw std::runtime_error(
    2525             :             "addmultisigaddress nrequired [\"key\",...] ( \"label\" )\n"
    2526             :             "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
    2527             :             "Each key is a PIVX address or hex-encoded public key.\n"
    2528             :             "If 'label' is specified, assign address to that label.\n"
    2529             : 
    2530             :             "\nArguments:\n"
    2531             :             "1. nrequired        (numeric, required) The number of required signatures out of the n keys or addresses.\n"
    2532             :             "2. \"keys\"         (string, required) A json array of pivx addresses or hex-encoded public keys\n"
    2533             :             "     [\n"
    2534             :             "       \"address\"  (string) pivx address or hex-encoded public key\n"
    2535             :             "       ...,\n"
    2536             :             "     ]\n"
    2537             :             "3. \"label\"        (string, optional) A label to assign the addresses to.\n"
    2538             : 
    2539             :             "\nResult:\n"
    2540             :             "\"pivxaddress\"  (string) A pivx address associated with the keys.\n"
    2541             : 
    2542             :             "\nExamples:\n"
    2543           0 :             "\nAdd a multisig address from 2 addresses\n" +
    2544           0 :             HelpExampleCli("addmultisigaddress", "2 \"[\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\",\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\"]\"") +
    2545           0 :             "\nAs json rpc call\n" +
    2546           0 :             HelpExampleRpc("addmultisigaddress", "2, \"[\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\",\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\"]\""));
    2547             : 
    2548          36 :     LOCK2(cs_main, pwallet->cs_wallet);
    2549             : 
    2550          24 :     std::string label;
    2551          12 :     if (request.params.size() > 2)
    2552           5 :         label = LabelFromValue(request.params[2]);
    2553             : 
    2554             :     // Construct using pay-to-script-hash:
    2555          24 :     CScript inner = _createmultisig_redeemScript(pwallet, request.params);
    2556          12 :     CScriptID innerID(inner);
    2557          12 :     pwallet->AddCScript(inner);
    2558             : 
    2559          12 :     pwallet->SetAddressBook(innerID, label, AddressBook::AddressBookPurpose::SEND);
    2560          24 :     return EncodeDestination(innerID);
    2561             : }
    2562             : 
    2563             : 
    2564             : struct tallyitem {
    2565             :     CAmount nAmount;
    2566             :     int nConf;
    2567             :     std::vector<uint256> txids;
    2568             :     bool fIsWatchonly;
    2569         615 :     tallyitem()
    2570           5 :     {
    2571         615 :         nAmount = 0;
    2572         615 :         nConf = std::numeric_limits<int>::max();
    2573           5 :         fIsWatchonly = false;
    2574             :     }
    2575             : };
    2576             : 
    2577          53 : static UniValue ListReceived(CWallet* const pwallet, const UniValue& params, bool by_label, int nBlockHeight)
    2578             : {
    2579             :     // Minimum confirmations
    2580          53 :     int nMinDepth = 1;
    2581          53 :     if (params.size() > 0)
    2582          48 :         nMinDepth = params[0].get_int();
    2583             : 
    2584             :     // Whether to include empty labels
    2585          53 :     bool fIncludeEmpty = false;
    2586          53 :     if (params.size() > 1)
    2587          46 :         fIncludeEmpty = params[1].get_bool();
    2588             : 
    2589          53 :     isminefilter filter = ISMINE_SPENDABLE_ALL;
    2590          53 :     if (params.size() > 2)
    2591          44 :         if (params[2].get_bool())
    2592          44 :             filter = filter | ISMINE_WATCH_ONLY;
    2593             : 
    2594          53 :     bool has_filtered_address = false;
    2595          53 :     CTxDestination filtered_address = CNoDestination();
    2596          53 :     if (!by_label && params.size() > 3) {
    2597          84 :         CTxDestination dest = DecodeDestination(params[3].get_str());
    2598          42 :         if (!IsValidDestination(dest)) {
    2599           2 :             throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
    2600             :         }
    2601          41 :         filtered_address = dest;
    2602          41 :         has_filtered_address = true;
    2603             :     }
    2604             : 
    2605             :     // Tally
    2606         104 :     std::map<CTxDestination, tallyitem> mapTally;
    2607        3131 :     for (const auto& entry : pwallet->mapWallet) {
    2608        3079 :         const CWalletTx& wtx = entry.second;
    2609             : 
    2610        3079 :         if (!IsFinalTx(wtx.tx, nBlockHeight)) {
    2611          17 :             continue;
    2612             :         }
    2613             : 
    2614        3079 :         int nDepth = wtx.GetDepthInMainChain();
    2615        3079 :         if (nDepth < nMinDepth) {
    2616          17 :             continue;
    2617             :         }
    2618             : 
    2619        6390 :         for (const CTxOut& txout : wtx.tx->vout) {
    2620        4077 :             CTxDestination address;
    2621        3328 :             if (!ExtractDestination(txout.scriptPubKey, address)) {
    2622        2579 :                 continue;
    2623             :             }
    2624             : 
    2625        3328 :             if (has_filtered_address && !(filtered_address == address)) {
    2626        2559 :                 continue;
    2627             :             }
    2628             : 
    2629         769 :             isminefilter mine = IsMine(*pwallet, address);
    2630         769 :             if (!(mine & filter)) {
    2631          20 :                 continue;
    2632             :             }
    2633             : 
    2634         749 :             tallyitem& item = mapTally[address];
    2635         749 :             item.nAmount += txout.nValue;
    2636         749 :             item.nConf = std::min(item.nConf, nDepth);
    2637         749 :             item.txids.push_back(wtx.GetHash());
    2638         749 :             if (mine & ISMINE_WATCH_ONLY)
    2639          20 :                 item.fIsWatchonly = true;
    2640             :         }
    2641             :     }
    2642             : 
    2643             :     // Create mapAddressBook iterator
    2644             :     // If we aren't filtering, go from begin() to end()
    2645          52 :     auto itAddr = pwallet->NewAddressBookIterator();
    2646             :     // If we are filtering, find() the applicable entry
    2647          52 :     if (has_filtered_address) {
    2648          41 :         itAddr.SetFilter(filtered_address);
    2649             :     }
    2650             : 
    2651             :     // Reply
    2652          52 :     UniValue ret(UniValue::VARR);
    2653         104 :     std::map<std::string, tallyitem> label_tally;
    2654             : 
    2655         246 :     for (auto& itAddrBook = itAddr; itAddrBook.IsValid(); itAddrBook.Next()) {
    2656             : 
    2657          71 :         auto* dest = itAddrBook.GetCTxDestKey();
    2658          79 :         if (!dest) continue;
    2659             : 
    2660          71 :         const auto &address = *dest;
    2661         134 :         const std::string &label = itAddrBook.GetValue().name;
    2662          71 :         auto it = mapTally.find(address);
    2663          71 :         if (it == mapTally.end() && !fIncludeEmpty) {
    2664           8 :             continue;
    2665             :         }
    2666             : 
    2667          63 :         CAmount nAmount = 0;
    2668          63 :         int nConf = std::numeric_limits<int>::max();
    2669          63 :         bool fIsWatchonly = false;
    2670          63 :         if (it != mapTally.end()) {
    2671          45 :             nAmount = (*it).second.nAmount;
    2672          45 :             nConf = (*it).second.nConf;
    2673          45 :             fIsWatchonly = (*it).second.fIsWatchonly;
    2674             :         }
    2675             : 
    2676          63 :         if (by_label) {
    2677          15 :             tallyitem& _item = label_tally[label];
    2678          15 :             _item.nAmount += nAmount;
    2679          15 :             _item.nConf = std::min(_item.nConf, nConf);
    2680          15 :             _item.fIsWatchonly = fIsWatchonly;
    2681             :         } else {
    2682          96 :             UniValue obj(UniValue::VOBJ);
    2683          48 :             if (fIsWatchonly)
    2684          32 :                 obj.pushKV("involvesWatchonly", true);
    2685          96 :             obj.pushKV("address", EncodeDestination(address, AddressBook::IsColdStakingPurpose(label), AddressBook::IsExchangePurpose(label)));
    2686          96 :             obj.pushKV("amount", ValueFromAmount(nAmount));
    2687          48 :             if (nConf == std::numeric_limits<int>::max()) nConf = 0;
    2688          48 :             obj.pushKV("confirmations", nConf);
    2689          48 :             obj.pushKV("bcconfirmations", nConf);       // DEPRECATED in 4.3.99
    2690          48 :             obj.pushKV("label", label);
    2691          96 :             UniValue transactions(UniValue::VARR);
    2692          48 :             if (it != mapTally.end()) {
    2693          72 :                 for (const uint256 &item : (*it).second.txids) {
    2694          78 :                     transactions.push_back(item.GetHex());
    2695             :                 }
    2696             :             }
    2697          48 :             obj.pushKV("txids", transactions);
    2698          48 :             ret.push_back(obj);
    2699             :         }
    2700             :     }
    2701             : 
    2702          52 :     if (by_label) {
    2703           9 :         for (const auto& entry : label_tally) {
    2704           5 :             CAmount nAmount = entry.second.nAmount;
    2705           5 :             int nConf = entry.second.nConf;
    2706          10 :             UniValue obj(UniValue::VOBJ);
    2707           5 :             if (entry.second.fIsWatchonly)
    2708           0 :                 obj.pushKV("involvesWatchonly", true);
    2709          10 :             obj.pushKV("amount", ValueFromAmount(nAmount));
    2710           6 :             obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
    2711           5 :             obj.pushKV("label", entry.first);
    2712           5 :             ret.push_back(obj);
    2713             :         }
    2714             :     }
    2715             : 
    2716         104 :     return ret;
    2717             : }
    2718             : 
    2719          49 : UniValue listreceivedbyaddress(const JSONRPCRequest& request)
    2720             : {
    2721          49 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2722             : 
    2723          49 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2724           0 :         return NullUniValue;
    2725             : 
    2726          49 :     if (request.fHelp || request.params.size() > 4)
    2727           0 :         throw std::runtime_error(
    2728             :             "listreceivedbyaddress ( minconf include_empty include_watchonly filter)\n"
    2729             :             "\nList balances by receiving address.\n"
    2730             : 
    2731             :             "\nArguments:\n"
    2732             :             "1. minconf           (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
    2733             :             "2. include_empty     (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
    2734             :             "3. include_watchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
    2735             :             "4. filter            (string, optional) If present, only return information on this address.\n"
    2736             : 
    2737             :             "\nResult:\n"
    2738             :             "[\n"
    2739             :             "  {\n"
    2740             :             "    \"involvesWatchonly\" : \"true\",    (bool) Only returned if imported addresses were involved in transaction\n"
    2741             :             "    \"address\" : \"receivingaddress\",  (string) The receiving address\n"
    2742             :             "    \"amount\" : x.xxx,                  (numeric) The total amount in PIV received by the address\n"
    2743             :             "    \"confirmations\" : n                (numeric) The number of confirmations of the most recent transaction included\n"
    2744             :             "    \"bcconfirmations\" : n,             (numeric) DEPRECATED: Will be removed in a future release\n"
    2745             :             "    \"label\" : \"label\",               (string) The label of the receiving address. The default label is \"\".\n"
    2746             :             "  }\n"
    2747             :             "  ,...\n"
    2748             :             "]\n"
    2749             : 
    2750           0 :             "\nExamples:\n" +
    2751           0 :             HelpExampleCli("listreceivedbyaddress", "") +
    2752           0 :             HelpExampleCli("listreceivedbyaddress", "6 true") +
    2753           0 :             HelpExampleRpc("listreceivedbyaddress", "6, true, true") +
    2754           0 :             HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\""));
    2755             : 
    2756             :     // Make sure the results are valid at least up to the most recent block
    2757             :     // the user could have gotten from another RPC command prior to now
    2758          49 :     pwallet->BlockUntilSyncedToCurrentChain();
    2759             : 
    2760         146 :     LOCK2(cs_main, pwallet->cs_wallet);
    2761          49 :     int nBlockHeight = chainActive.Height();
    2762          49 :     return ListReceived(pwallet, request.params, false, nBlockHeight);
    2763             : }
    2764             : 
    2765          17 : UniValue listreceivedbyshieldaddress(const JSONRPCRequest& request)
    2766             : {
    2767          17 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2768             : 
    2769          17 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2770           0 :         return NullUniValue;
    2771             : 
    2772          17 :     if (request.fHelp || request.params.size()==0 || request.params.size() >2)
    2773           0 :         throw std::runtime_error(
    2774             :                 "listreceivedbyshieldaddress \"address\" ( minconf )\n"
    2775             :                 "\nReturn a list of amounts received by a shield addr belonging to the node's wallet.\n"
    2776             : 
    2777             :                 "\nArguments:\n"
    2778             :                 "1. \"address\"      (string) The private address.\n"
    2779             :                 "2. minconf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
    2780             : 
    2781             :                 "\nResult:\n"
    2782             :                 "{\n"
    2783             :                 "  \"txid\": \"txid\",           (string) the transaction id\n"
    2784             :                 "  \"amount\": xxxxx,         (numeric) the amount of value in the note\n"
    2785             :                 "  \"memo\": xxxxx,           (string) hexadecimal string representation of memo field\n"
    2786             :                 "  \"confirmations\" : n,     (numeric) the number of confirmations\n"
    2787             :                 "  \"blockheight\": n,         (numeric) The block height containing the transaction\n"
    2788             :                 "  \"blockindex\": n,         (numeric) The block index containing the transaction.\n"
    2789             :                 "  \"blocktime\": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
    2790             :                 "  \"outindex\" (sapling) : n,     (numeric) the output index\n"
    2791             :                 "  \"change\": true|false,    (boolean) true if the address that received the note is also one of the sending addresses\n"
    2792             :                 "}\n"
    2793             : 
    2794             :                 "\nExamples:\n"
    2795           0 :                 + HelpExampleCli("listreceivedbyshieldaddress", "\"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\"")
    2796           0 :                 + HelpExampleRpc("listreceivedbyshieldaddress", "\"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\"")
    2797           0 :         );
    2798             : 
    2799             :     // Make sure the results are valid at least up to the most recent block
    2800             :     // the user could have gotten from another RPC command prior to now
    2801          17 :     pwallet->BlockUntilSyncedToCurrentChain();
    2802             : 
    2803          48 :     LOCK2(cs_main, pwallet->cs_wallet);
    2804             : 
    2805          17 :     int nMinDepth = 1;
    2806          17 :     if (request.params.size() > 1) {
    2807           6 :         nMinDepth = request.params[1].get_int();
    2808             :     }
    2809           6 :     if (nMinDepth < 0) {
    2810           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
    2811             :     }
    2812             : 
    2813             :     // Check that the from address is valid.
    2814          32 :     auto fromaddress = request.params[0].get_str();
    2815             : 
    2816          30 :     auto zaddr = KeyIO::DecodeSaplingPaymentAddress(fromaddress);
    2817          16 :     if (!zaddr) {
    2818           2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid addr.");
    2819             :     }
    2820          15 :     libzcash::SaplingPaymentAddress shieldAddr = *zaddr;
    2821             : 
    2822          15 :     auto sspkm = pwallet->GetSaplingScriptPubKeyMan();
    2823             :     // Visitor to support Sapling addrs
    2824          15 :     if (!sspkm->PaymentAddressBelongsToWallet(shieldAddr)) {
    2825           2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, shield addr spending key or viewing key not found.");
    2826             :     }
    2827             : 
    2828          28 :     UniValue result(UniValue::VARR);
    2829          28 :     std::vector<SaplingNoteEntry> saplingEntries;
    2830          14 :     sspkm->GetFilteredNotes(saplingEntries, zaddr, nMinDepth, false, false);
    2831             : 
    2832          28 :     std::set<std::pair<libzcash::PaymentAddress, uint256>> nullifierSet;
    2833          14 :     bool hasSpendingKey = pwallet->HaveSpendingKeyForPaymentAddress(shieldAddr);
    2834          14 :     if (hasSpendingKey) {
    2835          39 :         nullifierSet = sspkm->GetNullifiersForAddresses({*zaddr});
    2836             :     }
    2837             : 
    2838          55 :     for (const SaplingNoteEntry& entry : saplingEntries) {
    2839          82 :         UniValue obj(UniValue::VOBJ);
    2840          82 :         obj.pushKV("txid", entry.op.hash.ToString());
    2841          82 :         obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value())));
    2842          82 :         obj.pushKV("memo", HexStrTrimmed(entry.memo));
    2843          41 :         obj.pushKV("outindex", (int)entry.op.n);
    2844          41 :         obj.pushKV("confirmations", entry.confirmations);
    2845             : 
    2846          41 :         int height = 0;
    2847          41 :         int index = -1;
    2848          41 :         int64_t time = 0;
    2849             : 
    2850          41 :         auto it = pwallet->mapWallet.find(entry.op.hash);
    2851          41 :         if (it != pwallet->mapWallet.end()) {
    2852          41 :             const CWalletTx& wtx = it->second;
    2853          82 :             if (!wtx.m_confirm.hashBlock.IsNull())
    2854          40 :                 height = mapBlockIndex[wtx.m_confirm.hashBlock]->nHeight;
    2855          41 :             index = wtx.m_confirm.nIndex;
    2856          41 :             time = wtx.GetTxTime();
    2857             :         }
    2858             : 
    2859          41 :         obj.pushKV("blockheight", height);
    2860          41 :         obj.pushKV("blockindex", index);
    2861          41 :         obj.pushKV("blocktime", time);
    2862             : 
    2863          41 :         if (hasSpendingKey) {
    2864          76 :             obj.pushKV("change", sspkm->IsNoteSaplingChange(nullifierSet, entry.address, entry.op));
    2865             :         }
    2866          41 :         result.push_back(obj);
    2867             :     }
    2868          14 :     return result;
    2869             : }
    2870             : 
    2871           4 : UniValue listreceivedbylabel(const JSONRPCRequest& request)
    2872             : {
    2873           4 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2874             : 
    2875           4 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2876           0 :         return NullUniValue;
    2877             : 
    2878           4 :     if (request.fHelp || request.params.size() > 3)
    2879           0 :         throw std::runtime_error(
    2880             :             "listreceivedbylabel ( minconf include_empty include_watchonly)\n"
    2881             :             "\nList received transactions by label.\n"
    2882             : 
    2883             :             "\nArguments:\n"
    2884             :             "1. minconf           (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
    2885             :             "2. include_empty     (boolean, optional, default=false) Whether to include labels that haven't received any payments.\n"
    2886             :             "3. include_watchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
    2887             : 
    2888             :             "\nResult:\n"
    2889             :             "[\n"
    2890             :             "  {\n"
    2891             :             "    \"involvesWatchonly\" : \"true\",    (bool) Only returned if imported addresses were involved in transaction\n"
    2892             :             "    \"amount\" : x.xxx,                  (numeric) The total amount received by addresses with this label\n"
    2893             :             "    \"confirmations\" : n                (numeric) The number of confirmations of the most recent transaction included\n"
    2894             :             "    \"bcconfirmations\" : n,             (numeric) DEPRECATED: Will be removed in a future release\n"
    2895             :             "    \"label\" : \"label\"                (string) The label of the receiving address. The default label is \"\".\n"
    2896             :             "  }\n"
    2897             :             "  ,...\n"
    2898             :             "]\n"
    2899             : 
    2900           0 :             "\nExamples:\n" +
    2901           0 :             HelpExampleCli("listreceivedbylabel", "") + HelpExampleCli("listreceivedbylabel", "6 true") + HelpExampleRpc("listreceivedbylabel", "6, true, true"));
    2902             : 
    2903             :     // Make sure the results are valid at least up to the most recent block
    2904             :     // the user could have gotten from another RPC command prior to now
    2905           4 :     pwallet->BlockUntilSyncedToCurrentChain();
    2906             : 
    2907          12 :     LOCK2(cs_main, pwallet->cs_wallet);
    2908           4 :     int nBlockHeight = chainActive.Height();
    2909           4 :     return ListReceived(pwallet, request.params, true, nBlockHeight);
    2910             : }
    2911             : 
    2912           3 : UniValue listcoldutxos(const JSONRPCRequest& request)
    2913             : {
    2914           3 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2915             : 
    2916           3 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2917           0 :         return NullUniValue;
    2918             : 
    2919           3 :     if (request.fHelp || request.params.size() > 1)
    2920           0 :         throw std::runtime_error(
    2921             :             "listcoldutxos ( not_whitelisted )\n"
    2922             :             "\nList P2CS unspent outputs received by this wallet as cold-staker-\n"
    2923             : 
    2924             :             "\nArguments:\n"
    2925             :             "1. not_whitelisted   (boolean, optional, default=false) Whether to exclude P2CS from whitelisted delegators.\n"
    2926             : 
    2927             :             "\nResult:\n"
    2928             :             "[\n"
    2929             :             "  {\n"
    2930             :             "    \"txid\" : \"true\",            (string) The transaction id of the P2CS utxo\n"
    2931             :             "    \"txidn\" : n                 (numeric) The output number of the P2CS utxo\n"
    2932             :             "    \"amount\" : x.xxx,           (numeric) The amount of the P2CS utxo\n"
    2933             :             "    \"confirmations\" : n         (numeric) The number of confirmations of the P2CS utxo\n"
    2934             :             "    \"cold-staker\" : \"address\"   (string) The cold-staker address of the P2CS utxo\n"
    2935             :             "    \"coin-owner\" : \"address\"    (string) The coin-owner address of the P2CS utxo\n"
    2936             :             "    \"whitelisted\" : \"true\"      (boolean) \"true\"/\"false\" coin-owner in delegator whitelist\n"
    2937             :             "  }\n"
    2938             :             "  ,...\n"
    2939             :             "]\n"
    2940             : 
    2941           0 :             "\nExamples:\n" +
    2942           0 :             HelpExampleCli("listcoldutxos", "") + HelpExampleCli("listcoldutxos", "true"));
    2943             : 
    2944             :     // Make sure the results are valid at least up to the most recent block
    2945             :     // the user could have gotten from another RPC command prior to now
    2946           3 :     pwallet->BlockUntilSyncedToCurrentChain();
    2947             : 
    2948           9 :     LOCK2(cs_main, pwallet->cs_wallet);
    2949             : 
    2950           3 :     bool fExcludeWhitelisted = false;
    2951           3 :     if (request.params.size() > 0)
    2952           0 :         fExcludeWhitelisted = request.params[0].get_bool();
    2953           6 :     UniValue results(UniValue::VARR);
    2954             : 
    2955         264 :     for (const auto& entry : pwallet->mapWallet) {
    2956         261 :         const uint256& wtxid = entry.first;
    2957         261 :         const CWalletTx* pcoin = &entry.second;
    2958         261 :         if (!CheckFinalTx(pcoin->tx) || !pcoin->IsTrusted())
    2959           2 :             continue;
    2960             : 
    2961             :         // if this tx has no unspent P2CS outputs for us, skip it
    2962         259 :         if(pcoin->GetColdStakingCredit() == 0 && pcoin->GetStakeDelegationCredit() == 0)
    2963         216 :             continue;
    2964             : 
    2965         127 :         for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
    2966          84 :             const CTxOut& out = pcoin->tx->vout[i];
    2967          84 :             isminetype mine = pwallet->IsMine(out);
    2968          84 :             if (!bool(mine & ISMINE_COLD) && !bool(mine & ISMINE_SPENDABLE_DELEGATED))
    2969          41 :                 continue;
    2970          43 :             txnouttype type;
    2971          86 :             std::vector<CTxDestination> addresses;
    2972          43 :             int nRequired;
    2973          43 :             if (!ExtractDestinations(out.scriptPubKey, type, addresses, nRequired))
    2974           0 :                 continue;
    2975          43 :             const bool fWhitelisted = pwallet->HasAddressBook(addresses[1]) > 0;
    2976          43 :             if (fExcludeWhitelisted && fWhitelisted)
    2977           0 :                 continue;
    2978          86 :             UniValue entry(UniValue::VOBJ);
    2979          86 :             entry.pushKV("txid", wtxid.GetHex());
    2980          43 :             entry.pushKV("txidn", (int)i);
    2981          86 :             entry.pushKV("amount", ValueFromAmount(out.nValue));
    2982          43 :             entry.pushKV("confirmations", pcoin->GetDepthInMainChain());
    2983          86 :             entry.pushKV("cold-staker", EncodeDestination(addresses[0], CChainParams::STAKING_ADDRESS));
    2984          86 :             entry.pushKV("coin-owner", EncodeDestination(addresses[1]));
    2985          47 :             entry.pushKV("whitelisted", fWhitelisted ? "true" : "false");
    2986          43 :             results.push_back(entry);
    2987             :         }
    2988             :     }
    2989             : 
    2990           3 :     return results;
    2991             : }
    2992             : 
    2993         408 : static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
    2994             : {
    2995         408 :     if (IsValidDestination(dest))
    2996        1209 :         entry.pushKV("address", EncodeDestination(dest));
    2997         408 : }
    2998             : 
    2999         326 : static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
    3000             : {
    3001         326 :     AssertLockHeld(cs_main);
    3002             : 
    3003         326 :     CAmount nFee;
    3004         326 :     std::list<COutputEntry> listReceived;
    3005         326 :     std::list<COutputEntry> listSent;
    3006             : 
    3007         326 :     wtx.GetAmounts(listReceived, listSent, nFee, filter);
    3008             : 
    3009         326 :     bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
    3010             : 
    3011             :     // Sent
    3012         326 :     if ((!listSent.empty() || nFee != 0)) {
    3013         209 :         for (const COutputEntry& s : listSent) {
    3014         234 :             UniValue entry(UniValue::VOBJ);
    3015         117 :             if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY))
    3016           0 :                 entry.pushKV("involvesWatchonly", true);
    3017         117 :             MaybePushAddress(entry, s.destination);
    3018         117 :             entry.pushKV("category", "send");
    3019         234 :             entry.pushKV("amount", ValueFromAmount(-s.amount));
    3020         117 :             if (pwallet->HasAddressBook(s.destination)) {
    3021         110 :                 entry.pushKV("label", pwallet->GetNameForAddressBookEntry(s.destination));
    3022             :             }
    3023         117 :             entry.pushKV("vout", s.vout);
    3024         234 :             entry.pushKV("fee", ValueFromAmount(-nFee));
    3025         117 :             if (fLong)
    3026          55 :                 WalletTxToJSON(wtx, entry);
    3027         117 :             ret.push_back(entry);
    3028             :         }
    3029             :     }
    3030             : 
    3031             :     // Received
    3032         326 :     int depth = wtx.GetDepthInMainChain();
    3033         326 :     if (listReceived.size() > 0 && depth >= nMinDepth) {
    3034         568 :         for (const COutputEntry& r : listReceived) {
    3035         582 :             std::string label;
    3036         291 :             if (pwallet->HasAddressBook(r.destination))
    3037          81 :                 label = pwallet->GetNameForAddressBookEntry(r.destination);
    3038         582 :             UniValue entry(UniValue::VOBJ);
    3039         291 :             if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY))
    3040           2 :                 entry.pushKV("involvesWatchonly", true);
    3041         291 :             MaybePushAddress(entry, r.destination);
    3042         291 :             if (wtx.IsCoinBase()) {
    3043         210 :                 if (depth < 1)
    3044           0 :                     entry.pushKV("category", "orphan");
    3045         210 :                 else if (wtx.GetBlocksToMaturity() > 0)
    3046         312 :                     entry.pushKV("category", "immature");
    3047             :                 else
    3048         108 :                     entry.pushKV("category", "generate");
    3049             :             } else {
    3050         162 :                 entry.pushKV("category", "receive");
    3051             :             }
    3052         582 :             entry.pushKV("amount", ValueFromAmount(r.amount));
    3053         291 :             if (pwallet->HasAddressBook(r.destination)) {
    3054         162 :                 entry.pushKV("label", label);
    3055             :             }
    3056         291 :             entry.pushKV("vout", r.vout);
    3057         291 :             if (fLong)
    3058         261 :                 WalletTxToJSON(wtx, entry);
    3059         291 :             ret.push_back(entry);
    3060             :         }
    3061             :     }
    3062         326 : }
    3063             : 
    3064          23 : UniValue listtransactions(const JSONRPCRequest& request)
    3065             : {
    3066          23 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3067             : 
    3068          23 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3069           0 :         return NullUniValue;
    3070             : 
    3071          23 :     if (request.fHelp || request.params.size() > 6) throw std::runtime_error(
    3072             :             "listtransactions ( \"dummy\" count from include_watchonly include_delegated include_cold)\n"
    3073             :             "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n"
    3074             : 
    3075             :             "\nArguments:\n"
    3076             :             "1. \"dummy\"         (string, optional) If set, should be \"*\" for backwards compatibility.\n"
    3077             :             "2. count             (numeric, optional, default=10) The number of transactions to return\n"
    3078             :             "3. from              (numeric, optional, default=0) The number of transactions to skip\n"
    3079             :             "4. include_watchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
    3080             :             "5. include_delegated (bool, optional, default=true) Also include balance delegated to cold stakers\n"
    3081             :             "6. include_cold      (bool, optional, default=true) Also include delegated balance received as cold-staker by this node\n"
    3082             : 
    3083             :             "\nResult:\n"
    3084             :             "[\n"
    3085             :             "  {\n"
    3086             :             "    \"address\":\"pivxaddress\",    (string) The pivx address of the transaction.\n"
    3087             :             "    \"category\":\"category\",      (string) The transaction category (send|receive|orphan|immature|generate).\n"
    3088             :             "    \"amount\": x.xxx,          (numeric) The amount in PIV. This is negative for the 'send' category, and positive\n"
    3089             :             "                                         for the 'receive' category,\n"
    3090             :             "    \"vout\" : n,               (numeric) the vout value\n"
    3091             :             "    \"fee\": x.xxx,             (numeric) The amount of the fee in PIV. This is negative and only available for the \n"
    3092             :             "                                         'send' category of transactions.\n"
    3093             :             "    \"confirmations\": n,     (numeric) The number of blockchain confirmations for the transaction. Available for 'send'\n"
    3094             :             "                                         'receive' category of transactions. Negative confirmations indicate the\n"
    3095             :             "                                         transaction conflicts with the block chain\n"
    3096             :             "    \"bcconfirmations\" : n,         (numeric) DEPRECATED: Will be removed in a future release\n"
    3097             :             "    \"trusted\": xxx            (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n"
    3098             :             "                                          and 'receive' category of transactions.\n"
    3099             :             "    \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
    3100             :             "                                          category of transactions.\n"
    3101             :             "    \"blockindex\": n,          (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
    3102             :             "                                          category of transactions.\n"
    3103             :             "    \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
    3104             :             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
    3105             :             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
    3106             :             "                                          for 'send' and 'receive' category of transactions.\n"
    3107             :             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
    3108             :             "  }\n"
    3109             :             "]\n"
    3110             : 
    3111             :             "\nExamples:\n"
    3112           0 :             "\nList the most recent 10 transactions in the systems\n" +
    3113           0 :             HelpExampleCli("listtransactions", "") +
    3114           0 :             "\nList transactions 100 to 120\n" +
    3115           0 :             HelpExampleCli("listtransactions", "\"*\" 20 100") +
    3116           0 :             "\nAs a json rpc call\n" +
    3117           0 :             HelpExampleRpc("listtransactions", "\"*\", 20, 100")
    3118           0 :         );
    3119             : 
    3120             :     // Make sure the results are valid at least up to the most recent block
    3121             :     // the user could have gotten from another RPC command prior to now
    3122          23 :     pwallet->BlockUntilSyncedToCurrentChain();
    3123             : 
    3124          69 :     LOCK2(cs_main, pwallet->cs_wallet);
    3125             : 
    3126          23 :     if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
    3127           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\"");
    3128             :     }
    3129          23 :     int nCount = 10;
    3130          23 :     if (request.params.size() > 1)
    3131           4 :         nCount = request.params[1].get_int();
    3132          23 :     int nFrom = 0;
    3133          23 :     if (request.params.size() > 2)
    3134           2 :         nFrom = request.params[2].get_int();
    3135          23 :     isminefilter filter = ISMINE_SPENDABLE;
    3136          23 :     if ( request.params.size() > 3 && request.params[3].get_bool() )
    3137           1 :             filter = filter | ISMINE_WATCH_ONLY;
    3138          23 :     if ( !(request.params.size() > 4) || request.params[4].get_bool() )
    3139          23 :         filter = filter | ISMINE_SPENDABLE_DELEGATED;
    3140          23 :     if ( !(request.params.size() > 5) || request.params[5].get_bool() )
    3141          23 :         filter = filter | ISMINE_COLD;
    3142             : 
    3143          23 :     if (nCount < 0)
    3144           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
    3145          23 :     if (nFrom < 0)
    3146           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
    3147             : 
    3148          46 :     UniValue ret(UniValue::VARR);
    3149             : 
    3150          23 :     const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
    3151             : 
    3152             :     // iterate backwards until we have nCount items to return:
    3153         267 :     for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
    3154         264 :         CWalletTx* const pwtx = (*it).second;
    3155         264 :         ListTransactions(pwallet, *pwtx, 0, true, ret, filter);
    3156         264 :         if ((int)ret.size() >= (nCount + nFrom)) break;
    3157             :     }
    3158             :     // ret is newest to oldest
    3159             : 
    3160          23 :     if (nFrom > (int)ret.size())
    3161           0 :         nFrom = ret.size();
    3162          23 :     if ((nFrom + nCount) > (int)ret.size())
    3163           3 :         nCount = ret.size() - nFrom;
    3164             : 
    3165          46 :     std::vector<UniValue> arrTmp = ret.getValues();
    3166             : 
    3167          23 :     std::vector<UniValue>::iterator first = arrTmp.begin();
    3168          23 :     std::advance(first, nFrom);
    3169          23 :     std::vector<UniValue>::iterator last = arrTmp.begin();
    3170          23 :     std::advance(last, nFrom+nCount);
    3171             : 
    3172          23 :     if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
    3173          23 :     if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
    3174             : 
    3175          23 :     std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
    3176             : 
    3177          23 :     ret.clear();
    3178          23 :     ret.setArray();
    3179          23 :     ret.push_backV(arrTmp);
    3180             : 
    3181          23 :     return ret;
    3182             : }
    3183             : 
    3184           2 : UniValue listsinceblock(const JSONRPCRequest& request)
    3185             : {
    3186           2 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3187             : 
    3188           2 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3189           0 :         return NullUniValue;
    3190             : 
    3191           2 :     if (request.fHelp || request.params.size() > 3)
    3192           0 :         throw std::runtime_error(
    3193             :             "listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n"
    3194             :             "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
    3195             : 
    3196             :             "\nArguments:\n"
    3197             :             "1. \"blockhash\"         (string, optional) The block hash to list transactions since\n"
    3198             :             "2. target_confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
    3199             :             "3. include_watchonly:    (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
    3200             : 
    3201             :             "\nResult:\n"
    3202             :             "{\n"
    3203             :             "  \"transactions\": [\n"
    3204             :             "    \"address\":\"pivxaddress\",    (string) The pivx address of the transaction. Not present for move transactions (category = move).\n"
    3205             :             "    \"category\":\"send|receive\",     (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
    3206             :             "    \"amount\": x.xxx,          (numeric) The amount in PIV. This is negative for the 'send' category, and for the 'move' category for moves \n"
    3207             :             "                                          outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
    3208             :             "    \"vout\" : n,               (numeric) the vout value\n"
    3209             :             "    \"fee\": x.xxx,             (numeric) The amount of the fee in PIV. This is negative and only available for the 'send' category of transactions.\n"
    3210             :             "    \"confirmations\": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
    3211             :             "    \"bcconfirmations\" : n,             (numeric) DEPRECATED: Will be removed in a future release\n"
    3212             :             "    \"blockhash\": \"hashvalue\",     (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
    3213             :             "    \"blockindex\": n,          (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
    3214             :             "    \"blocktime\": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
    3215             :             "    \"txid\": \"transactionid\",  (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
    3216             :             "    \"time\": xxx,              (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
    3217             :             "    \"timereceived\": xxx,      (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
    3218             :             "    \"comment\": \"...\",       (string) If a comment is associated with the transaction.\n"
    3219             :             "    \"label\" : \"label\"       (string) A comment for the address/transaction, if any\n"
    3220             :             "    \"to\": \"...\",            (string) If a comment to is associated with the transaction.\n"
    3221             :             "  ],\n"
    3222             :             "  \"lastblock\": \"lastblockhash\"     (string) The hash of the last block\n"
    3223             :             "}\n"
    3224             : 
    3225           0 :             "\nExamples:\n" +
    3226           0 :             HelpExampleCli("listsinceblock", "") +
    3227           0 :             HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6") +
    3228           0 :             HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6"));
    3229             : 
    3230             :     // Make sure the results are valid at least up to the most recent block
    3231             :     // the user could have gotten from another RPC command prior to now
    3232           2 :     pwallet->BlockUntilSyncedToCurrentChain();
    3233             : 
    3234           6 :     LOCK2(cs_main, pwallet->cs_wallet);
    3235             : 
    3236           2 :     CBlockIndex* pindex = nullptr;
    3237           2 :     int target_confirms = 1;
    3238           2 :     isminefilter filter = ISMINE_SPENDABLE_ALL | ISMINE_COLD;
    3239             : 
    3240           2 :     if (request.params.size() > 0) {
    3241           2 :         uint256 blockId(ParseHashV(request.params[0], "blockhash"));
    3242           2 :         pindex = LookupBlockIndex(blockId);
    3243             :     }
    3244             : 
    3245           2 :     if (request.params.size() > 1) {
    3246           0 :         target_confirms = request.params[1].get_int();
    3247             : 
    3248           0 :         if (target_confirms < 1)
    3249           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
    3250             :     }
    3251             : 
    3252           2 :     if (request.params.size() > 2)
    3253           0 :         if (request.params[2].get_bool())
    3254           0 :             filter = filter | ISMINE_WATCH_ONLY;
    3255             : 
    3256           2 :     int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
    3257             : 
    3258           4 :     UniValue transactions(UniValue::VARR);
    3259             : 
    3260          22 :     for (const auto& entry : pwallet->mapWallet) {
    3261          20 :         const CWalletTx& tx = entry.second;
    3262             : 
    3263          20 :         if (depth == -1 || tx.GetDepthInMainChain() < depth)
    3264           1 :             ListTransactions(pwallet, tx, 0, true, transactions, filter);
    3265             :     }
    3266             : 
    3267           2 :     CBlockIndex* pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
    3268           2 :     uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : UINT256_ZERO;
    3269             : 
    3270           4 :     UniValue ret(UniValue::VOBJ);
    3271           2 :     ret.pushKV("transactions", transactions);
    3272           4 :     ret.pushKV("lastblock", lastblock.GetHex());
    3273             : 
    3274           2 :     return ret;
    3275             : }
    3276             : 
    3277          63 : UniValue gettransaction(const JSONRPCRequest& request)
    3278             : {
    3279          63 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3280             : 
    3281          63 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3282           0 :         return NullUniValue;
    3283             : 
    3284          63 :     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
    3285           0 :         throw std::runtime_error(
    3286             :             "gettransaction \"txid\" ( include_watchonly )\n"
    3287             :             "\nGet detailed information about in-wallet transaction \"txid\"\n"
    3288             : 
    3289             :             "\nArguments:\n"
    3290             :             "1. \"txid\"              (string, required) The transaction id\n"
    3291             :             "2. \"include_watchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
    3292             : 
    3293             :             "\nResult:\n"
    3294             :             "{\n"
    3295             :             "  \"amount\" : x.xxx,        (numeric) The transaction amount in PIV\n"
    3296             :             "  \"confirmations\" : n,     (numeric) The number of confirmations\n"
    3297             :             "  \"bcconfirmations\" : n,             (numeric) DEPRECATED: Will be removed in a future release\n"
    3298             :             "  \"blockhash\" : \"hash\",  (string) The block hash\n"
    3299             :             "  \"blockindex\" : xx,       (numeric) The block index\n"
    3300             :             "  \"blocktime\" : ttt,       (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
    3301             :             "  \"txid\" : \"transactionid\",   (string) The transaction id.\n"
    3302             :             "  \"time\" : ttt,            (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
    3303             :             "  \"timereceived\" : ttt,    (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
    3304             :             "  \"details\" : [\n"
    3305             :             "    {\n"
    3306             :             "      \"address\" : \"pivxaddress\",   (string) The pivx address involved in the transaction\n"
    3307             :             "      \"category\" : \"send|receive\",    (string) The category, either 'send' or 'receive'\n"
    3308             :             "      \"amount\" : x.xxx                  (numeric) The amount in PIV\n"
    3309             :             "      \"label\" : \"label\",              (string) A comment for the address/transaction, if any\n"
    3310             :             "      \"vout\" : n,                       (numeric) the vout value\n"
    3311             :             "    }\n"
    3312             :             "    ,...\n"
    3313             :             "  ],\n"
    3314             :             "  \"hex\" : \"data\"         (string) Raw data for transaction\n"
    3315             :             "}\n"
    3316             : 
    3317           0 :             "\nExamples:\n" +
    3318           0 :             HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") +
    3319           0 :             HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true") +
    3320           0 :             HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\""));
    3321             : 
    3322             :     // Make sure the results are valid at least up to the most recent block
    3323             :     // the user could have gotten from another RPC command prior to now
    3324          63 :     pwallet->BlockUntilSyncedToCurrentChain();
    3325             : 
    3326         187 :     LOCK2(cs_main, pwallet->cs_wallet);
    3327             : 
    3328          63 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    3329             : 
    3330          63 :     isminefilter filter = ISMINE_SPENDABLE_ALL | ISMINE_COLD;
    3331          63 :     if (request.params.size() > 1)
    3332           2 :         if (request.params[1].get_bool())
    3333           2 :             filter = filter | ISMINE_WATCH_ONLY;
    3334             : 
    3335         124 :     UniValue entry(UniValue::VOBJ);
    3336          63 :     auto it = pwallet->mapWallet.find(hash);
    3337          63 :     if (it == pwallet->mapWallet.end()) {
    3338           4 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
    3339             :     }
    3340          61 :     const CWalletTx& wtx = it->second;
    3341             : 
    3342          61 :     CAmount nCredit = wtx.GetCredit(filter);
    3343          61 :     CAmount nDebit = wtx.GetDebit(filter);
    3344          61 :     CAmount nNet = nCredit - nDebit;
    3345          61 :     CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
    3346             : 
    3347         122 :     entry.pushKV("amount", ValueFromAmount(nNet - nFee));
    3348          61 :     if (wtx.IsFromMe(filter))
    3349         124 :         entry.pushKV("fee", ValueFromAmount(nFee));
    3350             : 
    3351          61 :     WalletTxToJSON(wtx, entry);
    3352             : 
    3353          61 :     UniValue details(UniValue::VARR);
    3354          61 :     ListTransactions(pwallet, wtx, 0, false, details, filter);
    3355          61 :     entry.pushKV("details", details);
    3356             : 
    3357         122 :     std::string strHex = EncodeHexTx(*wtx.tx);
    3358          61 :     entry.pushKV("hex", strHex);
    3359             : 
    3360          61 :     return entry;
    3361             : }
    3362             : 
    3363           3 : UniValue abandontransaction(const JSONRPCRequest& request)
    3364             : {
    3365           3 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3366             : 
    3367           3 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3368           0 :         return NullUniValue;
    3369             : 
    3370           3 :     if (request.fHelp || request.params.size() != 1)
    3371           0 :         throw std::runtime_error(
    3372             :                 "abandontransaction \"txid\"\n"
    3373             :                 "\nMark in-wallet transaction \"txid\" as abandoned\n"
    3374             :                 "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
    3375             :                 "for their inputs to be respent.  It can be used to replace \"stuck\" or evicted transactions.\n"
    3376             :                 "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
    3377             :                 "It has no effect on transactions which are already abandoned.\n"
    3378             :                 "\nArguments:\n"
    3379             :                 "1. \"txid\"    (string, required) The transaction id\n"
    3380             :                 "\nResult:\n"
    3381             :                 "\nExamples:\n"
    3382           0 :                 + HelpExampleCli("abandontransaction",
    3383             :                                  "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    3384           0 :                 + HelpExampleRpc("abandontransaction",
    3385             :                                  "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    3386           0 :         );
    3387             : 
    3388             :     // Make sure the results are valid at least up to the most recent block
    3389             :     // the user could have gotten from another RPC command prior to now
    3390           3 :     pwallet->BlockUntilSyncedToCurrentChain();
    3391             : 
    3392           7 :     LOCK2(cs_main, pwallet->cs_wallet);
    3393             : 
    3394           3 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    3395             : 
    3396           3 :     if (!pwallet->mapWallet.count(hash))
    3397           2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
    3398           2 :     if (!pwallet->AbandonTransaction(hash))
    3399           2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
    3400             : 
    3401           1 :     return NullUniValue;
    3402             : }
    3403             : 
    3404             : 
    3405           9 : UniValue backupwallet(const JSONRPCRequest& request)
    3406             : {
    3407           9 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3408             : 
    3409           9 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3410           0 :         return NullUniValue;
    3411             : 
    3412           9 :     if (request.fHelp || request.params.size() != 1)
    3413           0 :         throw std::runtime_error(
    3414             :             "backupwallet \"destination\"\n"
    3415             :             "\nSafely copies wallet file to destination, which can be a directory or a path with filename.\n"
    3416             : 
    3417             :             "\nArguments:\n"
    3418             :             "1. \"destination\"   (string) The destination directory or file\n"
    3419             : 
    3420           0 :             "\nExamples:\n" +
    3421           0 :             HelpExampleCli("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backup.dat\""));
    3422             : 
    3423             :     // Make sure the results are valid at least up to the most recent block
    3424             :     // the user could have gotten from another RPC command prior to now
    3425           9 :     pwallet->BlockUntilSyncedToCurrentChain();
    3426             : 
    3427          23 :     LOCK2(cs_main, pwallet->cs_wallet);
    3428             : 
    3429          18 :     std::string strDest = request.params[0].get_str();
    3430           9 :     if (!pwallet->BackupWallet(strDest))
    3431           8 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
    3432             : 
    3433           5 :     return NullUniValue;
    3434             : }
    3435             : 
    3436             : 
    3437           8 : UniValue keypoolrefill(const JSONRPCRequest& request)
    3438             : {
    3439           8 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3440             : 
    3441           8 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3442           0 :         return NullUniValue;
    3443             : 
    3444           8 :     if (request.fHelp || request.params.size() > 1)
    3445           0 :         throw std::runtime_error(
    3446             :             "keypoolrefill ( newsize )\n"
    3447           0 :             "\nFills the keypool." +
    3448           0 :             HelpRequiringPassphrase(pwallet) + "\n"
    3449             : 
    3450             :             "\nArguments\n"
    3451             :             "1. newsize     (numeric, optional, default=100) The new keypool size\n"
    3452             : 
    3453           0 :             "\nExamples:\n" +
    3454           0 :             HelpExampleCli("keypoolrefill", "") + HelpExampleRpc("keypoolrefill", ""));
    3455             : 
    3456          24 :     LOCK2(cs_main, pwallet->cs_wallet);
    3457             : 
    3458             :     // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
    3459           8 :     unsigned int kpSize = 0;
    3460           8 :     if (request.params.size() > 0) {
    3461           6 :         if (request.params[0].get_int() < 0)
    3462           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
    3463           6 :         kpSize = (unsigned int)request.params[0].get_int();
    3464             :     }
    3465             : 
    3466           8 :     EnsureWalletIsUnlocked(pwallet);
    3467           8 :     pwallet->TopUpKeyPool(kpSize);
    3468             : 
    3469           8 :     if (pwallet->GetKeyPoolSize() < kpSize)
    3470           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
    3471             : 
    3472           8 :     return NullUniValue;
    3473             : }
    3474             : 
    3475             : 
    3476           2 : static void LockWallet(CWallet* pWallet)
    3477             : {
    3478           2 :     LOCK(pWallet->cs_wallet);
    3479           2 :     pWallet->nRelockTime = 0;
    3480           2 :     pWallet->fWalletUnlockStaking = false;
    3481           2 :     pWallet->Lock();
    3482           2 : }
    3483             : 
    3484          18 : UniValue walletpassphrase(const JSONRPCRequest& request)
    3485             : {
    3486          18 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3487             : 
    3488          18 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3489           0 :         return NullUniValue;
    3490             : 
    3491          18 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) {
    3492           0 :         throw std::runtime_error(
    3493             :             "walletpassphrase \"passphrase\" timeout ( staking_only )\n"
    3494             :             "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
    3495             :             "This is needed prior to performing transactions related to private keys such as sending PIVs\n"
    3496             : 
    3497             :             "\nArguments:\n"
    3498             :             "1. \"passphrase\"     (string, required) The wallet passphrase\n"
    3499             :             "2. timeout            (numeric, required) The time to keep the decryption key in seconds.\n"
    3500             :             "3. staking_only       (boolean, optional, default=false) If is true sending functions are disabled."
    3501             : 
    3502             :             "\nNote:\n"
    3503             :             "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
    3504             :             "time that overrides the old one. A timeout of \"0\" unlocks until the wallet is closed.\n"
    3505             : 
    3506             :             "\nExamples:\n"
    3507           0 :             "\nUnlock the wallet for 60 seconds\n" +
    3508           0 :             HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
    3509           0 :             "\nUnlock the wallet for 60 seconds but allow staking only\n" +
    3510           0 :             HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60 true") +
    3511           0 :             "\nLock the wallet again (before 60 seconds)\n" +
    3512           0 :             HelpExampleCli("walletlock", "") +
    3513           0 :             "\nAs json rpc call\n" +
    3514           0 :             HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60"));
    3515             :     }
    3516             : 
    3517          50 :     LOCK2(cs_main, pwallet->cs_wallet);
    3518             : 
    3519          18 :     if (request.fHelp)
    3520           0 :         return true;
    3521          18 :     if (!pwallet->IsCrypted())
    3522           0 :         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
    3523             : 
    3524             :     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
    3525          36 :     SecureString strWalletPass;
    3526          18 :     strWalletPass.reserve(100);
    3527             :     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    3528             :     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
    3529          18 :     strWalletPass = request.params[0].get_str().c_str();
    3530             : 
    3531          18 :     bool stakingOnly = false;
    3532          18 :     if (request.params.size() == 3)
    3533           2 :         stakingOnly = request.params[2].get_bool();
    3534             : 
    3535          18 :     if (!pwallet->IsLocked() && pwallet->fWalletUnlockStaking && stakingOnly)
    3536           2 :         throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked.");
    3537             : 
    3538             :     // Get the timeout
    3539          17 :     int64_t nSleepTime = request.params[1].get_int64();
    3540             :     // Timeout cannot be negative, otherwise it will relock immediately
    3541          17 :     if (nSleepTime < 0) {
    3542           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
    3543             :     }
    3544             :     // Clamp timeout
    3545          16 :     constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
    3546          16 :     if (nSleepTime > MAX_SLEEP_TIME) {
    3547           1 :         nSleepTime = MAX_SLEEP_TIME;
    3548             :     }
    3549             : 
    3550          16 :     if (!pwallet->Unlock(strWalletPass, stakingOnly))
    3551           4 :         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
    3552             : 
    3553          14 :     pwallet->TopUpKeyPool();
    3554             : 
    3555          14 :     if (nSleepTime > 0) {
    3556          14 :         pwallet->nRelockTime = GetTime () + nSleepTime;
    3557          46 :         RPCRunLater (strprintf("lockwallet(%s)", pwallet->GetName()), std::bind (LockWallet, pwallet), nSleepTime);
    3558             :     }
    3559             : 
    3560          14 :     return NullUniValue;
    3561             : }
    3562             : 
    3563             : 
    3564           1 : UniValue walletpassphrasechange(const JSONRPCRequest& request)
    3565             : {
    3566           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3567             : 
    3568           1 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3569           0 :         return NullUniValue;
    3570             : 
    3571           1 :     if (request.fHelp || request.params.size() != 2) {
    3572           0 :         throw std::runtime_error(
    3573             :             "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
    3574             :             "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
    3575             : 
    3576             :             "\nArguments:\n"
    3577             :             "1. \"oldpassphrase\"      (string) The current passphrase\n"
    3578             :             "2. \"newpassphrase\"      (string) The new passphrase\n"
    3579             : 
    3580           0 :             "\nExamples:\n" +
    3581           0 :             HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\""));
    3582             :     }
    3583             : 
    3584           3 :     LOCK2(cs_main, pwallet->cs_wallet);
    3585             : 
    3586           1 :     if (request.fHelp)
    3587           0 :         return true;
    3588           1 :     if (!pwallet->IsCrypted())
    3589           0 :         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
    3590             : 
    3591             :     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
    3592             :     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
    3593           2 :     SecureString strOldWalletPass;
    3594           1 :     strOldWalletPass.reserve(100);
    3595           1 :     strOldWalletPass = request.params[0].get_str().c_str();
    3596             : 
    3597           2 :     SecureString strNewWalletPass;
    3598           1 :     strNewWalletPass.reserve(100);
    3599           1 :     strNewWalletPass = request.params[1].get_str().c_str();
    3600             : 
    3601           1 :     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
    3602           0 :         throw std::runtime_error(
    3603             :             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
    3604           0 :             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
    3605             : 
    3606           1 :     if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
    3607           0 :         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
    3608             : 
    3609           1 :     return NullUniValue;
    3610             : }
    3611             : 
    3612             : 
    3613           5 : UniValue walletlock(const JSONRPCRequest& request)
    3614             : {
    3615           5 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3616             : 
    3617           5 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3618           0 :         return NullUniValue;
    3619             : 
    3620           5 :     if (request.fHelp || !request.params.empty()) {
    3621           0 :         throw std::runtime_error(
    3622             :             "walletlock\n"
    3623             :             "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
    3624             :             "After calling this method, you will need to call walletpassphrase again\n"
    3625             :             "before being able to call any methods which require the wallet to be unlocked.\n"
    3626             : 
    3627             :             "\nExamples:\n"
    3628           0 :             "\nSet the passphrase for 2 minutes to perform a transaction\n" +
    3629           0 :             HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
    3630           0 :             "\nPerform a send (requires passphrase set)\n" +
    3631           0 :             HelpExampleCli("sendtoaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" 1.0") +
    3632           0 :             "\nClear the passphrase since we are done before 2 minutes is up\n" +
    3633           0 :             HelpExampleCli("walletlock", "") +
    3634           0 :             "\nAs json rpc call\n" +
    3635           0 :             HelpExampleRpc("walletlock", ""));
    3636             :     }
    3637             : 
    3638             :     // Make sure the results are valid at least up to the most recent block
    3639             :     // the user could have gotten from another RPC command prior to now
    3640           5 :     pwallet->BlockUntilSyncedToCurrentChain();
    3641             : 
    3642          15 :     LOCK2(cs_main, pwallet->cs_wallet);
    3643             : 
    3644           5 :     if (request.fHelp)
    3645           0 :         return true;
    3646           5 :     if (!pwallet->IsCrypted())
    3647           0 :         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
    3648             : 
    3649           5 :     pwallet->Lock();
    3650           5 :     pwallet->nRelockTime = 0;
    3651             : 
    3652           5 :     return NullUniValue;
    3653             : }
    3654             : 
    3655             : 
    3656           7 : UniValue encryptwallet(const JSONRPCRequest& request)
    3657             : {
    3658           7 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3659             : 
    3660           7 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3661           0 :         return NullUniValue;
    3662             : 
    3663           7 :     if (request.fHelp || request.params.size() != 1) {
    3664           0 :         throw std::runtime_error(
    3665             :             "encryptwallet \"passphrase\"\n"
    3666             :             "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
    3667             :             "After this, any calls that interact with private keys such as sending or signing \n"
    3668             :             "will require the passphrase to be set prior the making these calls.\n"
    3669             :             "Use the walletpassphrase call for this, and then walletlock call.\n"
    3670             :             "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
    3671             : 
    3672             :             "\nArguments:\n"
    3673             :             "1. \"passphrase\"    (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
    3674             : 
    3675             :             "\nExamples:\n"
    3676           0 :             "\nEncrypt you wallet\n" +
    3677           0 :             HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
    3678           0 :             "\nNow set the passphrase to use the wallet, such as for signing or sending PIVs\n" +
    3679           0 :             HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
    3680           0 :             "\nNow we can so something like sign\n" +
    3681           0 :             HelpExampleCli("signmessage", "\"pivxaddress\" \"test message\"") +
    3682           0 :             "\nNow lock the wallet again by removing the passphrase\n" +
    3683           0 :             HelpExampleCli("walletlock", "") +
    3684           0 :             "\nAs a json rpc call\n" +
    3685           0 :             HelpExampleRpc("encryptwallet", "\"my pass phrase\""));
    3686             :     }
    3687             : 
    3688          20 :     LOCK2(cs_main, pwallet->cs_wallet);
    3689             : 
    3690           7 :     if (request.fHelp)
    3691           0 :         return true;
    3692           7 :     if (pwallet->IsCrypted())
    3693           2 :         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
    3694             : 
    3695             :     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    3696             :     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
    3697          12 :     SecureString strWalletPass;
    3698           6 :     strWalletPass.reserve(100);
    3699           6 :     strWalletPass = request.params[0].get_str().c_str();
    3700             : 
    3701           6 :     if (strWalletPass.length() < 1)
    3702           0 :         throw std::runtime_error(
    3703             :             "encryptwallet <passphrase>\n"
    3704           0 :             "Encrypts the wallet with <passphrase>.");
    3705             : 
    3706           6 :     if (!pwallet->EncryptWallet(strWalletPass))
    3707           0 :         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
    3708             : 
    3709           6 :     return "wallet encrypted; The keypool has been flushed, you need to make a new backup.";
    3710             : }
    3711             : 
    3712         104 : UniValue listunspent(const JSONRPCRequest& request)
    3713             : {
    3714         104 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3715             : 
    3716         104 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3717           0 :         return NullUniValue;
    3718             : 
    3719         104 :     if (request.fHelp || request.params.size() > 6)
    3720           0 :         throw std::runtime_error(
    3721             :                 "listunspent ( minconf maxconf  [\"address\",...] watchonly_config [query_options] include_unsafe)\n"
    3722             :                 "\nReturns array of unspent transaction outputs\n"
    3723             :                 "with between minconf and maxconf (inclusive) confirmations.\n"
    3724             :                 "Optionally filter to only include txouts paid to specified addresses.\n"
    3725             :                 "Results are an array of Objects, each of which has:\n"
    3726             :                 "{txid, vout, scriptPubKey, amount, confirmations, spendable}\n"
    3727             : 
    3728             :                 "\nArguments:\n"
    3729             :                 "1. minconf          (numeric, optional, default=1) The minimum confirmations to filter\n"
    3730             :                 "2. maxconf          (numeric, optional, default=9999999) The maximum confirmations to filter\n"
    3731             :                 "3. \"addresses\"    (string) A json array of pivx addresses to filter\n"
    3732             :                 "    [\n"
    3733             :                 "      \"address\"   (string) pivx address\n"
    3734             :                 "      ,...\n"
    3735             :                 "    ]\n"
    3736             :                 "4. watchonly_config (numeric, optional, default=1) 1 = list regular unspent transactions,  2 = list all unspent transactions (including watchonly)\n"
    3737             :                 "5. query_options    (json, optional) JSON with query options\n"
    3738             :                 "    {\n"
    3739           0 :                 "      \"minimumAmount\"    (numeric or string, default=0) Minimum value of each UTXO in " + CURRENCY_UNIT + "\n"
    3740           0 :                 "      \"maximumAmount\"    (numeric or string, default=unlimited) Maximum value of each UTXO in " + CURRENCY_UNIT + "\n"
    3741             :                 "      \"maximumCount\"     (numeric or string, default=unlimited) Maximum number of UTXOs\n"
    3742           0 :                 "      \"minimumSumAmount\" (numeric or string, default=unlimited) Minimum sum value of all UTXOs in " + CURRENCY_UNIT + "\n"
    3743             :                 "    }\n"
    3744             :                 "6. include_unsafe   (bool, optional, default=true) Include outputs that are not safe to spend\n"
    3745             :                 "                        See description of \"safe\" attribute below.\n"
    3746             : 
    3747             :                 "\nResult\n"
    3748             :                 "[                   (array of json object)\n"
    3749             :                 "  {\n"
    3750             :                 "    \"txid\" : \"txid\",        (string) the transaction id\n"
    3751             :                 "    \"generated\" : true|false  (boolean) true if txout is a coinstake transaction output\n"
    3752             :                 "    \"vout\" : n,               (numeric) the vout value\n"
    3753             :                 "    \"address\" : \"address\",  (string) the pivx address\n"
    3754             :                 "    \"label\" : \"label\",      (string) The associated label, or \"\" for the default label\n"
    3755             :                 "    \"scriptPubKey\" : \"key\", (string) the script key\n"
    3756             :                 "    \"redeemScript\" : \"key\", (string) the redeemscript key\n"
    3757             :                 "    \"amount\" : x.xxx,         (numeric) the transaction amount in PIV\n"
    3758             :                 "    \"confirmations\" : n,      (numeric) The number of confirmations\n"
    3759             :                 "    \"spendable\" : true|false  (boolean) Whether we have the private keys to spend this output\n"
    3760             :                 "    \"solvable\" : xxx          (boolean) Whether we know how to spend this output, ignoring the lack of keys\n"
    3761             :                 "    \"safe\" : xxx              (boolean) Whether this output is considered safe to spend. Unconfirmed transactions\n"
    3762             :                 "                              from outside keys and unconfirmed replacement transactions are considered unsafe\n"
    3763             :                 "                              and are not eligible for spending by fundrawtransaction and sendtoaddress.\n"
    3764             :                 "  }\n"
    3765             :                 "  ,...\n"
    3766             :                 "]\n"
    3767             : 
    3768           0 :                 "\nExamples\n" +
    3769           0 :                 HelpExampleCli("listunspent", "") + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
    3770           0 :                 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
    3771           0 :                 + HelpExampleCli("listunspent", "6 9999999 '[]' 1 '{ \"minimumAmount\": 0.005 }'")
    3772           0 :                 + HelpExampleCli("listunspent", "6 9999999 '[]' 1 '{ \"minimumAmount\": 0.005 }' false")
    3773           0 :                 + HelpExampleRpc("listunspent", "6, 9999999, [] , 1, { \"minimumAmount\": 0.005 } ")
    3774           0 :                 );
    3775             : 
    3776             :     // Make sure the results are valid at least up to the most recent block
    3777             :     // the user could have gotten from another RPC command prior to now
    3778         104 :     pwallet->BlockUntilSyncedToCurrentChain();
    3779             : 
    3780         104 :     int nMinDepth = 1;
    3781         104 :     if (request.params.size() > 0) {
    3782          39 :         RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
    3783          39 :         nMinDepth = request.params[0].get_int();
    3784             :     }
    3785             : 
    3786         104 :     int nMaxDepth = 9999999;
    3787         104 :     if (request.params.size() > 1) {
    3788          34 :         RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
    3789          34 :         nMaxDepth = request.params[1].get_int();
    3790             :     }
    3791             : 
    3792         104 :     CWallet::AvailableCoinsFilter coinFilter;
    3793             : 
    3794         208 :     std::set<CTxDestination> destinations;
    3795         104 :     if (request.params.size() > 2) {
    3796          33 :         RPCTypeCheckArgument(request.params[2], UniValue::VARR);
    3797          33 :         UniValue inputs = request.params[2].get_array();
    3798          36 :         for (unsigned int inx = 0; inx < inputs.size(); inx++) {
    3799           3 :             const UniValue& input = inputs[inx];
    3800           6 :             CTxDestination dest = DecodeDestination(input.get_str());
    3801           3 :             if (!IsValidDestination(dest))
    3802           0 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid PIVX address: ") + input.get_str());
    3803           3 :             if (destinations.count(dest))
    3804           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
    3805           3 :             destinations.insert(dest);
    3806             :         }
    3807          33 :         coinFilter.onlyFilteredDest = &destinations;
    3808             :     }
    3809             : 
    3810             :     // List watch only utxo
    3811         104 :     int nWatchonlyConfig = 1;
    3812         104 :     if(request.params.size() > 3) {
    3813          30 :         RPCTypeCheckArgument(request.params[3], UniValue::VNUM);
    3814          30 :         nWatchonlyConfig = request.params[3].get_int();
    3815          30 :         if (nWatchonlyConfig > 2 || nWatchonlyConfig < 1)
    3816           0 :             nWatchonlyConfig = 1;
    3817             :     }
    3818             : 
    3819         104 :     if (request.params.size() > 4) {
    3820          29 :         const UniValue& options = request.params[4].get_obj();
    3821             : 
    3822         174 :         RPCTypeCheckObj(options,
    3823             :             {
    3824          29 :                     {"minimumAmount", UniValueType()},
    3825          29 :                     {"maximumAmount", UniValueType()},
    3826          29 :                     {"minimumSumAmount", UniValueType()},
    3827          29 :                     {"maximumCount", UniValueType(UniValue::VNUM)},
    3828             :             },
    3829         145 :             true, true);
    3830             : 
    3831          58 :         if (options.exists("minimumAmount")) {
    3832          17 :             coinFilter.nMinOutValue = AmountFromValue(options["minimumAmount"]);
    3833             :         }
    3834             : 
    3835          58 :         if (options.exists("maximumAmount")) {
    3836          13 :             coinFilter.nMaxOutValue = AmountFromValue(options["maximumAmount"]);
    3837             :         }
    3838             : 
    3839          87 :         if (options.exists("minimumSumAmount")) {
    3840           8 :             coinFilter.nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
    3841             :         }
    3842             : 
    3843          58 :         if (options.exists("maximumCount"))
    3844           4 :             coinFilter.nMaximumCount = options["maximumCount"].get_int64();
    3845             :     }
    3846             : 
    3847         208 :     CCoinControl coinControl;
    3848         104 :     coinControl.fAllowWatchOnly = nWatchonlyConfig == 2;
    3849             : 
    3850         104 :     bool include_unsafe = request.params.size() < 6 || request.params[5].get_bool();
    3851         104 :     coinFilter.fOnlySafe = !include_unsafe;
    3852             : 
    3853         208 :     UniValue results(UniValue::VARR);
    3854         208 :     std::vector<COutput> vecOutputs;
    3855             : 
    3856         312 :     LOCK2(cs_main, pwallet->cs_wallet);
    3857         104 :     pwallet->AvailableCoins(&vecOutputs, &coinControl, coinFilter);
    3858        2256 :     for (const COutput& out : vecOutputs) {
    3859        2152 :         if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
    3860          70 :             continue;
    3861             : 
    3862        2082 :         UniValue entry(UniValue::VOBJ);
    3863        4164 :         entry.pushKV("txid", out.tx->GetHash().GetHex());
    3864        2082 :         entry.pushKV("vout", out.i);
    3865        3326 :         entry.pushKV("generated", out.tx->IsCoinStake() || out.tx->IsCoinBase());
    3866        4164 :         CTxDestination address;
    3867        2082 :         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
    3868        2082 :         if (ExtractDestination(scriptPubKey, address)) {
    3869        4164 :             entry.pushKV("address", EncodeDestination(address));
    3870        2082 :             if (pwallet->HasAddressBook(address)) {
    3871        1094 :                 entry.pushKV("label", pwallet->GetNameForAddressBookEntry(address));
    3872             :             }
    3873        2082 :             if (scriptPubKey.IsPayToScriptHash()) {
    3874           5 :                 const CScriptID& hash = boost::get<CScriptID>(address);
    3875          10 :                 CScript redeemScript;
    3876           5 :                 if (pwallet->GetCScript(hash, redeemScript))
    3877          16 :                     entry.pushKV("redeemScript", HexStr(redeemScript));
    3878             :             }
    3879             :         }
    3880        6246 :         entry.pushKV("scriptPubKey", HexStr(scriptPubKey));
    3881        4164 :         entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
    3882        2082 :         entry.pushKV("confirmations", out.nDepth);
    3883        2082 :         entry.pushKV("spendable", out.fSpendable);
    3884        2082 :         entry.pushKV("solvable", out.fSolvable);
    3885        2082 :         entry.pushKV("safe", out.fSafe);
    3886        2082 :         results.push_back(entry);
    3887             :     }
    3888             : 
    3889         104 :     return results;
    3890             : }
    3891             : 
    3892          39 : UniValue fundrawtransaction(const JSONRPCRequest& request)
    3893             : {
    3894          39 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3895             : 
    3896          39 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3897           0 :         return NullUniValue;
    3898             : 
    3899          39 :     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
    3900           0 :         throw std::runtime_error(
    3901             :             "fundrawtransaction \"hexstring\" ( options )\n"
    3902             :             "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
    3903             :             "This will not modify existing inputs, and will add one change output to the outputs.\n"
    3904             :             "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
    3905             :             "The inputs added will not be signed, use signrawtransaction for that.\n"
    3906             :             "Note that all existing inputs must have their previous output transaction be in the wallet.\n"
    3907             :             "Note that all inputs selected must be of standard form and P2SH scripts must be "
    3908             :             "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
    3909             :             "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
    3910             :             "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n"
    3911             : 
    3912             :             "\nArguments:\n"
    3913             :             "1. \"hexstring\"    (string, required) The hex string of the raw transaction\n"
    3914             :             "2. options          (object, optional)\n"
    3915             :             "   {\n"
    3916             :             "     \"changeAddress\"     (string, optional, default pool address) The PIVX address to receive the change\n"
    3917             :             "     \"changePosition\"    (numeric, optional, default random) The index of the change output\n"
    3918             :             "     \"includeWatching\"   (boolean, optional, default false) Also select inputs which are watch only\n"
    3919             :             "     \"lockUnspents\"      (boolean, optional, default false) Lock selected unspent outputs\n"
    3920             :             "     \"feeRate\"           (numeric, optional, default 0=estimate) Set a specific feerate (PIV per KB)\n"
    3921             :             "     \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
    3922             :             "                              The fee will be equally deducted from the amount of each specified output.\n"
    3923             :             "                              The outputs are specified by their zero-based index, before any change output is added.\n"
    3924             :             "                              Those recipients will receive less PIV than you enter in their corresponding amount field.\n"
    3925             :             "                              If no outputs are specified here, the sender pays the fee.\n"
    3926             :             "                                  [vout_index,...]\n"
    3927             :             "   }\n"
    3928             :             "\nResult:\n"
    3929             :             "{\n"
    3930             :             "  \"hex\":       \"value\", (string)  The resulting raw transaction (hex-encoded string)\n"
    3931             :             "  \"fee\":       n,         (numeric) The fee added to the transaction\n"
    3932             :             "  \"changepos\": n          (numeric) The position of the added change output, or -1\n"
    3933             :             "}\n"
    3934             :             "\"hex\"             \n"
    3935             :             "\nExamples:\n"
    3936             :             "\nCreate a transaction with no inputs\n"
    3937           0 :             + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
    3938             :             "\nAdd sufficient unsigned inputs to meet the output value\n"
    3939           0 :             + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
    3940             :             "\nSign the transaction\n"
    3941           0 :             + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
    3942             :             "\nSend the transaction\n"
    3943           0 :             + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
    3944           0 :             );
    3945             : 
    3946             :     // Make sure the results are valid at least up to the most recent block
    3947             :     // the user could have gotten from another RPC command prior to now
    3948          39 :     pwallet->BlockUntilSyncedToCurrentChain();
    3949             : 
    3950          39 :     RPCTypeCheck(request.params, {UniValue::VSTR});
    3951             : 
    3952          73 :     CTxDestination changeAddress = CNoDestination();
    3953          39 :     int changePosition = -1;
    3954          39 :     bool includeWatching = false;
    3955          39 :     bool lockUnspents = false;
    3956          78 :     UniValue subtractFeeFromOutputs;
    3957          78 :     std::set<int> setSubtractFeeFromOutputs;
    3958          39 :     CFeeRate feeRate = CFeeRate(0);
    3959          39 :     bool overrideEstimatedFeerate = false;
    3960             : 
    3961          39 :     if (request.params.size() > 1) {
    3962          20 :         RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
    3963          28 :         UniValue options = request.params[1];
    3964         120 :         RPCTypeCheckObj(options,
    3965             :             {
    3966          15 :                 {"changeAddress", UniValueType(UniValue::VSTR)},
    3967          15 :                 {"changePosition", UniValueType(UniValue::VNUM)},
    3968          15 :                 {"includeWatching", UniValueType(UniValue::VBOOL)},
    3969          15 :                 {"lockUnspents", UniValueType(UniValue::VBOOL)},
    3970          15 :                 {"feeRate", UniValueType()}, // will be checked below
    3971          17 :                 {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
    3972             :             },
    3973         105 :             true, true);
    3974             : 
    3975          28 :         if (options.exists("changeAddress")) {
    3976           6 :             changeAddress = DecodeDestination(options["changeAddress"].get_str());
    3977             : 
    3978           3 :             if (!IsValidDestination(changeAddress))
    3979           2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid PIVX address");
    3980             :         }
    3981             : 
    3982          26 :         if (options.exists("changePosition"))
    3983           4 :             changePosition = options["changePosition"].get_int();
    3984             : 
    3985          26 :         if (options.exists("includeWatching"))
    3986           2 :             includeWatching = options["includeWatching"].get_bool();
    3987             : 
    3988          26 :         if (options.exists("lockUnspents"))
    3989           0 :             lockUnspents = options["lockUnspents"].get_bool();
    3990             : 
    3991          26 :         if (options.exists("feeRate")) {
    3992           4 :             feeRate = CFeeRate(AmountFromValue(options["feeRate"]));
    3993           4 :             overrideEstimatedFeerate = true;
    3994             :         }
    3995             : 
    3996          39 :         if (options.exists("subtractFeeFromOutputs")) {
    3997          10 :             subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
    3998             :         }
    3999             :     }
    4000             : 
    4001             :     // parse hex string from parameter
    4002          74 :     CMutableTransaction origTx;
    4003          37 :     if (!DecodeHexTx(origTx, request.params[0].get_str()))
    4004           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
    4005             : 
    4006          37 :     if (origTx.vout.size() == 0)
    4007           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
    4008             : 
    4009          37 :     if (changePosition != -1 && (changePosition < 0 || (unsigned int) changePosition > origTx.vout.size()))
    4010           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
    4011             : 
    4012          42 :     for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
    4013           6 :         int pos = subtractFeeFromOutputs[idx].get_int();
    4014           6 :         if (setSubtractFeeFromOutputs.count(pos))
    4015           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
    4016           6 :         if (pos < 0)
    4017           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
    4018           6 :         if (pos >= int(origTx.vout.size()))
    4019           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
    4020           6 :         setSubtractFeeFromOutputs.insert(pos);
    4021             :     }
    4022             : 
    4023          38 :     CMutableTransaction tx(origTx);
    4024          36 :     CAmount nFeeOut;
    4025          72 :     std::string strFailReason;
    4026          36 :     if(!pwallet->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate,
    4027             :                                  changePosition, strFailReason, includeWatching,
    4028             :                                  lockUnspents, setSubtractFeeFromOutputs, changeAddress)) {
    4029           2 :         throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
    4030             :     }
    4031             : 
    4032          68 :     UniValue result(UniValue::VOBJ);
    4033         102 :     result.pushKV("hex", EncodeHexTx(tx));
    4034          34 :     result.pushKV("changepos", changePosition);
    4035          68 :     result.pushKV("fee", ValueFromAmount(nFeeOut));
    4036             : 
    4037          34 :     return result;
    4038             : }
    4039             : 
    4040          19 : UniValue lockunspent(const JSONRPCRequest& request)
    4041             : {
    4042          19 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4043             : 
    4044          19 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4045           0 :         return NullUniValue;
    4046             : 
    4047          19 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
    4048           0 :         throw std::runtime_error(
    4049             :             "lockunspent unlock transparent [{\"txid\":\"txid\",\"vout\":n},...]\n"
    4050             :             "\nUpdates list of temporarily unspendable outputs.\n"
    4051             :             "Temporarily lock (unlock=false) or unlock (unlock=true) specified transparent (transparent=true) or shielded (transparent=false) transaction outputs.\n"
    4052             :             "A locked transaction output will not be chosen by automatic coin selection, when spending PIVs.\n"
    4053             :             "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
    4054             :             "is always cleared (by virtue of process exit) when a node stops or fails.\n"
    4055             :             "Also see the listunspent call\n"
    4056             : 
    4057             :             "\nArguments:\n"
    4058             :             "1. unlock            (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
    4059             :             "2. transparent       (boolean, required) Whether the given transaction outputs are transparent (true) or shielded (false)\n"
    4060             :             "2. \"transactions\"  (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
    4061             :             "     [           (json array of json objects)\n"
    4062             :             "       {\n"
    4063             :             "         \"txid\":\"id\",    (string) The transaction id\n"
    4064             :             "         \"vout\": n         (numeric) The output number\n"
    4065             :             "       }\n"
    4066             :             "       ,...\n"
    4067             :             "     ]\n"
    4068             : 
    4069             :             "\nResult:\n"
    4070             :             "true|false    (boolean) Whether the command was successful or not\n"
    4071             : 
    4072             :             "\nExamples:\n"
    4073           0 :             "\nList the unspent transactions\n" +
    4074           0 :             HelpExampleCli("listunspent", "") +
    4075           0 :             "\nLock an unspent transaction\n" +
    4076           0 :             HelpExampleCli("lockunspent", "false true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    4077           0 :             "\nList the locked transactions\n" +
    4078           0 :             HelpExampleCli("listlockunspent", "") +
    4079           0 :             "\nUnlock the transaction again\n" +
    4080           0 :             HelpExampleCli("lockunspent", "true true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    4081           0 :             "\nAs a json rpc call\n" +
    4082           0 :             HelpExampleRpc("lockunspent", "false false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\""));
    4083             : 
    4084             :     // Make sure the results are valid at least up to the most recent block
    4085             :     // the user could have gotten from another RPC command prior to now
    4086          19 :     pwallet->BlockUntilSyncedToCurrentChain();
    4087             : 
    4088          57 :     LOCK2(cs_main, pwallet->cs_wallet);
    4089             : 
    4090          19 :     if (request.params.size() == 2)
    4091           0 :         RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VBOOL});
    4092             :     else
    4093          38 :         RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VBOOL, UniValue::VARR});
    4094             : 
    4095          19 :     bool fUnlock = request.params[0].get_bool();
    4096          19 :     bool transparent = request.params[1].get_bool();
    4097             : 
    4098          19 :     if (request.params.size() == 2) {
    4099           0 :         if (fUnlock) transparent ? pwallet->UnlockAllCoins() : pwallet->UnlockAllNotes();
    4100           0 :         return true;
    4101             :     }
    4102             : 
    4103          19 :     UniValue output_request = request.params[2].get_array();
    4104             : 
    4105             :     // Create and validate the COutPoints first.
    4106          38 :     std::vector<COutPoint> outputs;
    4107          19 :     std::vector<SaplingOutPoint> saplingOutputs;
    4108          19 :     transparent ? outputs.reserve(output_request.size()) : saplingOutputs.reserve(output_request.size());
    4109             : 
    4110          38 :     for (unsigned int idx = 0; idx < output_request.size(); idx++) {
    4111          19 :         const UniValue& output = output_request[idx];
    4112          19 :         if (!output.isObject())
    4113           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
    4114          19 :         const UniValue& o = output.get_obj();
    4115             : 
    4116          76 :         RPCTypeCheckObj(o,
    4117             :             {
    4118          19 :                 {"txid", UniValueType(UniValue::VSTR)},
    4119          19 :                 {"vout", UniValueType(UniValue::VNUM)},
    4120          57 :             });
    4121             : 
    4122          19 :         const uint256 txid(ParseHashO(o, "txid"));
    4123             : 
    4124          19 :         const int nOutput = find_value(o, "vout").get_int();
    4125          19 :         if (nOutput < 0) {
    4126           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
    4127             :         }
    4128             : 
    4129          19 :         bool is_locked = false;
    4130             : 
    4131          19 :         const auto it = pwallet->mapWallet.find(txid);
    4132          19 :         if (it == pwallet->mapWallet.end()) {
    4133           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
    4134             :         }
    4135             : 
    4136          19 :         const CWalletTx& wtx = it->second;
    4137          19 :         if (transparent) {
    4138          17 :             const COutPoint outpt(txid, nOutput);
    4139          17 :             if (outpt.n >= wtx.tx->vout.size()) {
    4140           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
    4141             :             }
    4142             : 
    4143          17 :             if (pwallet->IsSpent(outpt.hash, outpt.n)) {
    4144           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
    4145             :             }
    4146          17 :             is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n);
    4147             :         } else {
    4148           2 :             const SaplingOutPoint op(txid, nOutput);
    4149           2 :             if (op.n >= wtx.tx->sapData->vShieldedOutput.size()) {
    4150           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
    4151             :             }
    4152           2 :             if (pwallet->IsSaplingSpent(op)) {
    4153           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
    4154             :             }
    4155           2 :             is_locked = pwallet->IsLockedNote(op);
    4156             :         }
    4157             : 
    4158          19 :         if (fUnlock && !is_locked) {
    4159           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
    4160             :         }
    4161             : 
    4162          19 :         if (!fUnlock && is_locked) {
    4163           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
    4164             :         }
    4165             : 
    4166          19 :         transparent ? outputs.push_back(COutPoint(txid, nOutput)) : saplingOutputs.push_back(SaplingOutPoint(txid, nOutput));
    4167             :     }
    4168             : 
    4169             :     // Atomically set (un)locked status for the outputs.
    4170          36 :     for (const COutPoint& outpt : outputs) {
    4171          17 :         if (fUnlock) pwallet->UnlockCoin(outpt);
    4172          16 :         else pwallet->LockCoin(outpt);
    4173             :     }
    4174             : 
    4175          21 :     for (const SaplingOutPoint& op : saplingOutputs) {
    4176           2 :         if (fUnlock) pwallet->UnlockNote(op);
    4177             :         else
    4178           1 :             pwallet->LockNote(op);
    4179             :     }
    4180             : 
    4181          19 :     return true;
    4182             : }
    4183             : 
    4184          14 : UniValue listlockunspent(const JSONRPCRequest& request)
    4185             : {
    4186          14 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4187             : 
    4188          14 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4189           0 :         return NullUniValue;
    4190             : 
    4191          14 :     if (request.fHelp || request.params.size() > 0)
    4192           0 :         throw std::runtime_error(
    4193             :             "listlockunspent\n"
    4194             :             "\nReturns list of temporarily unspendable outputs.\n"
    4195             :             "See the lockunspent call to lock and unlock transactions for spending.\n"
    4196             : 
    4197             :             "\nResult:\n"
    4198             :             "{\n"
    4199             :             "  \"transparent\": [                 (array of json objects)\n"
    4200             :             "     {\n"
    4201             :             "       \"txid\": \"transactionid\"     (string) The transaction id locked\n"
    4202             :             "       \"vout\": n                   (numeric) The vout value\n"
    4203             :             "     },\n"
    4204             :             "     ...\n"
    4205             :             "   ],\n"
    4206             :             "  \"shielded\": [                    (array of json objects)\n"
    4207             :             "     {\n"
    4208             :             "       \"txid\": \"transactionid\"     (string) The transaction id locked\n"
    4209             :             "       \"vShieldedOutput\": n        (numeric) The vout value\n"
    4210             :             "     },\n"
    4211             :             "     ...\n"
    4212             :             "   ],\n"
    4213             :             "}\n"
    4214             : 
    4215             :             "\nExamples:\n"
    4216           0 :             "\nList the unspent transactions\n" +
    4217           0 :             HelpExampleCli("listunspent", "") +
    4218           0 :             "\nLock an unspent transaction\n" +
    4219           0 :             HelpExampleCli("lockunspent", "false true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    4220           0 :             "\nList the locked transactions\n" +
    4221           0 :             HelpExampleCli("listlockunspent", "") +
    4222           0 :             "\nUnlock the transaction again\n" +
    4223           0 :             HelpExampleCli("lockunspent", "true true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    4224           0 :             "\nAs a json rpc call\n" +
    4225           0 :             HelpExampleRpc("listlockunspent", ""));
    4226             : 
    4227          42 :     LOCK2(cs_main, pwallet->cs_wallet);
    4228             : 
    4229             : 
    4230          28 :     UniValue ret(UniValue::VOBJ);
    4231          28 :     UniValue transparent(UniValue::VARR);
    4232          14 :     UniValue shielded(UniValue::VARR);
    4233             : 
    4234          28 :     std::set<COutPoint> vOutpts = pwallet->ListLockedCoins();
    4235          36 :     for (const COutPoint& outpt : vOutpts) {
    4236          44 :         UniValue o(UniValue::VOBJ);
    4237             : 
    4238          44 :         o.pushKV("txid", outpt.hash.GetHex());
    4239          22 :         o.pushKV("vout", (int)outpt.n);
    4240          22 :         transparent.push_back(o);
    4241             :     }
    4242             : 
    4243          28 :     std::set<SaplingOutPoint> sOps = pwallet->ListLockedNotes();
    4244          16 :     for (const SaplingOutPoint& op : sOps) {
    4245           4 :         UniValue o(UniValue::VOBJ);
    4246             : 
    4247           4 :         o.pushKV("txid", op.hash.GetHex());
    4248           2 :         o.pushKV("vShieldedOutput", (int)op.n);
    4249           2 :         shielded.push_back(o);
    4250             :     }
    4251          14 :     ret.pushKV("transparent", transparent);
    4252          14 :     ret.pushKV("shielded", shielded);
    4253          14 :     return ret;
    4254             : }
    4255             : 
    4256           7 : UniValue settxfee(const JSONRPCRequest& request)
    4257             : {
    4258           7 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4259             : 
    4260           7 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4261           0 :         return NullUniValue;
    4262             : 
    4263           7 :     if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
    4264           0 :         throw std::runtime_error(
    4265             :             "settxfee amount\n"
    4266             :             "\nSet the transaction fee per kB.\n"
    4267             : 
    4268             :             "\nArguments:\n"
    4269             :             "1. amount         (numeric, required) The transaction fee in PIV/kB rounded to the nearest 0.00000001\n"
    4270             : 
    4271             :             "\nResult\n"
    4272             :             "true|false        (boolean) Returns true if successful\n"
    4273           0 :             "\nExamples:\n" +
    4274           0 :             HelpExampleCli("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001"));
    4275             : 
    4276          21 :     LOCK2(cs_main, pwallet->cs_wallet);
    4277             : 
    4278             :     // Amount
    4279           7 :     CAmount nAmount = 0;
    4280           7 :     if (request.params[0].get_real() != 0.0)
    4281           6 :         nAmount = AmountFromValue(request.params[0]); // rejects 0.0 amounts
    4282             : 
    4283           7 :     payTxFee = CFeeRate(nAmount, 1000);
    4284           7 :     return true;
    4285             : }
    4286             : 
    4287          69 : UniValue getwalletinfo(const JSONRPCRequest& request)
    4288             : {
    4289          69 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4290             : 
    4291          68 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4292           0 :         return NullUniValue;
    4293             : 
    4294          66 :     if (request.fHelp || request.params.size() != 0)
    4295           0 :         throw std::runtime_error(
    4296             :             "getwalletinfo\n"
    4297             :             "Returns an object containing various wallet state info.\n"
    4298             : 
    4299             :             "\nResult:\n"
    4300             :             "{\n"
    4301             :             "  \"walletname\": xxxxx,                     (string) the wallet name\n"
    4302             :             "  \"walletversion\": xxxxx,                  (numeric) the wallet version\n"
    4303             :             "  \"balance\": xxxxxxx,                      (numeric) the total PIV balance of the wallet (cold balance excluded)\n"
    4304             :             "  \"delegated_balance\": xxxxx,              (numeric) the PIV balance held in P2CS (cold staking) contracts\n"
    4305             :             "  \"cold_staking_balance\": xx,              (numeric) the PIV balance held in cold staking addresses\n"
    4306             :             "  \"unconfirmed_balance\": xxx,              (numeric) the total unconfirmed balance of the wallet in PIV\n"
    4307             :             "  \"immature_delegated_balance\": xxxxxx,    (numeric) the delegated immature balance of the wallet in PIV\n"
    4308             :             "  \"immature_cold_staking_balance\": xxxxxx, (numeric) the cold-staking immature balance of the wallet in PIV\n"
    4309             :             "  \"immature_balance\": xxxxxx,              (numeric) the total immature balance of the wallet in PIV\n"
    4310             :             "  \"txcount\": xxxxxxx,                      (numeric) the total number of transactions in the wallet\n"
    4311             :             "  \"autocombine_enabled\": true|false,       (boolean) true if autocombine is enabled, otherwise false\n"
    4312             :             "  \"autocombine_threshold\": x.xxx,          (numeric) the current autocombine threshold in PIV\n"
    4313             :             "  \"keypoololdest\": xxxxxx,                 (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
    4314             :             "  \"keypoolsize\": xxxx,                     (numeric) how many new keys are pre-generated (only counts external keys)\n"
    4315             :             "  \"keypoolsize_hd_internal\": xxxx,         (numeric) how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)\n"
    4316             :             "  \"keypoolsize_hd_staking\": xxxx,          (numeric) how many new keys are pre-generated for staking use (used for staking contracts, only appears if the wallet is using this feature)\n"
    4317             :             "  \"unlocked_until\": ttt,                   (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
    4318             :             "  \"paytxfee\": x.xxxx                       (numeric) the transaction fee configuration, set in PIV/kB\n"
    4319             :             "  \"hdseedid\": \"<hash160>\"                (string, optional) the Hash160 of the HD seed (only present when HD is enabled)\n"
    4320             :             "  \"last_processed_block\": xxxxx,          (numeric) the last block processed block height\n"
    4321             :             "}\n"
    4322             : 
    4323           0 :             "\nExamples:\n" +
    4324           0 :             HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", ""));
    4325             : 
    4326             :     // Make sure the results are valid at least up to the most recent block
    4327             :     // the user could have gotten from another RPC command prior to now
    4328          66 :     pwallet->BlockUntilSyncedToCurrentChain();
    4329             : 
    4330         198 :     LOCK2(cs_main, pwallet->cs_wallet);
    4331             : 
    4332         132 :     UniValue obj(UniValue::VOBJ);
    4333          66 :     obj.pushKV("walletname", pwallet->GetName());
    4334          66 :     obj.pushKV("walletversion", pwallet->GetVersion());
    4335         132 :     obj.pushKV("balance", ValueFromAmount(pwallet->GetAvailableBalance()));
    4336         132 :     obj.pushKV("delegated_balance", ValueFromAmount(pwallet->GetDelegatedBalance()));
    4337         132 :     obj.pushKV("cold_staking_balance", ValueFromAmount(pwallet->GetColdStakingBalance()));
    4338         132 :     obj.pushKV("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance()));
    4339         132 :     obj.pushKV("immature_balance",    ValueFromAmount(pwallet->GetImmatureBalance()));
    4340         132 :     obj.pushKV("immature_delegated_balance",    ValueFromAmount(pwallet->GetImmatureDelegatedBalance()));
    4341         132 :     obj.pushKV("immature_cold_staking_balance",    ValueFromAmount(pwallet->GetImmatureColdStakingBalance()));
    4342          66 :     obj.pushKV("txcount", (int)pwallet->mapWallet.size());
    4343             : 
    4344             :     // Autocombine settings
    4345          66 :     obj.pushKV("autocombine_enabled", pwallet->fCombineDust);
    4346         132 :     obj.pushKV("autocombine_threshold", ValueFromAmount(pwallet->nAutoCombineThreshold));
    4347          66 :     obj.pushKV("autocombine_frequency", pwallet->frequency);
    4348             : 
    4349             :     // Keypool information
    4350          66 :     obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
    4351          66 :     size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
    4352          66 :     obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
    4353             : 
    4354          66 :     ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan();
    4355          66 :     if (spk_man) {
    4356          66 :         const CKeyID& seed_id = spk_man->GetHDChain().GetID();
    4357         132 :         if (!seed_id.IsNull()) {
    4358         195 :             obj.pushKV("hdseedid", seed_id.GetHex());
    4359             :         }
    4360             :     }
    4361          66 :     if (pwallet->IsHDEnabled()) {
    4362          65 :         obj.pushKV("keypoolsize_hd_internal",   (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
    4363         130 :         obj.pushKV("keypoolsize_hd_staking",   (int64_t)(pwallet->GetStakingKeyPoolSize()));
    4364             :     }
    4365             : 
    4366          66 :     if (pwallet->IsCrypted())
    4367          10 :         obj.pushKV("unlocked_until", pwallet->nRelockTime);
    4368         132 :     obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()));
    4369          66 :     obj.pushKV("last_processed_block", pwallet->GetLastBlockHeight());
    4370          66 :     return obj;
    4371             : }
    4372             : 
    4373           3 : UniValue listwallets(const JSONRPCRequest& request)
    4374             : {
    4375           3 :     if (request.fHelp || !request.params.empty())
    4376           0 :         throw std::runtime_error(
    4377             :             "listwallets\n"
    4378             :             "Returns a list of currently loaded wallets.\n"
    4379             :             "For full information on the wallet, use \"getwalletinfo\"\n"
    4380             :             "\nResult:\n"
    4381             :             "[                         (json array of strings)\n"
    4382             :             "  \"walletname\"            (string) the wallet name\n"
    4383             :             "   ...\n"
    4384             :             "]\n"
    4385             :             "\nExamples:\n"
    4386           0 :             + HelpExampleCli("listwallets", "")
    4387           0 :             + HelpExampleRpc("listwallets", "")
    4388           0 :         );
    4389             : 
    4390           6 :     UniValue obj(UniValue::VARR);
    4391             : 
    4392          16 :     for (CWalletRef pwallet : vpwallets) {
    4393          13 :         if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
    4394           0 :             return NullUniValue;
    4395             :         }
    4396             : 
    4397          26 :         LOCK(pwallet->cs_wallet);
    4398          13 :         obj.push_back(pwallet->GetName());
    4399             :     }
    4400             : 
    4401           3 :     return obj;
    4402             : }
    4403             : 
    4404         275 : UniValue getstakingstatus(const JSONRPCRequest& request)
    4405             : {
    4406         275 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4407             : 
    4408         275 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4409           0 :         return NullUniValue;
    4410             : 
    4411         275 :     if (request.fHelp || request.params.size() != 0)
    4412           0 :         throw std::runtime_error(
    4413             :             "getstakingstatus\n"
    4414             :             "\nReturns an object containing various staking information.\n"
    4415             : 
    4416             :             "\nResult:\n"
    4417             :             "{\n"
    4418             :             "  \"staking_status\": true|false,      (boolean) whether the wallet is staking or not\n"
    4419             :             "  \"staking_enabled\": true|false,     (boolean) whether staking is enabled/disabled in pivx.conf\n"
    4420             :             "  \"coldstaking_enabled\": true|false, (boolean) whether cold-staking is enabled/disabled in pivx.conf\n"
    4421             :             "  \"haveconnections\": true|false,     (boolean) whether network connections are present\n"
    4422             :             "  \"mnsync\": true|false,              (boolean) whether the required masternode/spork data is synced\n"
    4423             :             "  \"walletunlocked\": true|false,      (boolean) whether the wallet is unlocked\n"
    4424             :             "  \"stakeablecoins\": n                (numeric) number of stakeable UTXOs\n"
    4425             :             "  \"stakingbalance\": d                (numeric) PIV value of the stakeable coins (minus reserve balance, if any)\n"
    4426             :             "  \"stakesplitthreshold\": d           (numeric) value of the current threshold for stake split\n"
    4427             :             "  \"lastattempt_age\": n               (numeric) seconds since last stake attempt\n"
    4428             :             "  \"lastattempt_depth\": n             (numeric) depth of the block on top of which the last stake attempt was made\n"
    4429             :             "  \"lastattempt_hash\": xxx            (hex string) hash of the block on top of which the last stake attempt was made\n"
    4430             :             "  \"lastattempt_coins\": n             (numeric) number of stakeable coins available during last stake attempt\n"
    4431             :             "  \"lastattempt_tries\": n             (numeric) number of stakeable coins checked during last stake attempt\n"
    4432             :             "}\n"
    4433             : 
    4434           0 :             "\nExamples:\n" +
    4435           0 :             HelpExampleCli("getstakingstatus", "") + HelpExampleRpc("getstakingstatus", ""));
    4436             : 
    4437             : 
    4438         275 :     if (!pwallet)
    4439           0 :         throw JSONRPCError(RPC_IN_WARMUP, "Try again after active chain is loaded");
    4440         275 :     {
    4441         825 :         LOCK2(cs_main, &pwallet->cs_wallet);
    4442         550 :         UniValue obj(UniValue::VOBJ);
    4443         275 :         obj.pushKV("staking_status", pwallet->pStakerStatus->IsActive());
    4444         550 :         obj.pushKV("staking_enabled", gArgs.GetBoolArg("-staking", DEFAULT_STAKING));
    4445         275 :         bool fColdStaking = gArgs.GetBoolArg("-coldstaking", true);
    4446         275 :         obj.pushKV("coldstaking_enabled", fColdStaking);
    4447         275 :         obj.pushKV("haveconnections", (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) > 0));
    4448         275 :         obj.pushKV("mnsync", !masternodeSync.NotCompleted());
    4449         275 :         obj.pushKV("walletunlocked", !pwallet->IsLocked());
    4450         550 :         std::vector<CStakeableOutput> vCoins;
    4451         275 :         pwallet->StakeableCoins(&vCoins);
    4452         275 :         obj.pushKV("stakeablecoins", (int)vCoins.size());
    4453         550 :         obj.pushKV("stakingbalance", ValueFromAmount(pwallet->GetStakingBalance(fColdStaking)));
    4454         550 :         obj.pushKV("stakesplitthreshold", ValueFromAmount(pwallet->nStakeSplitThreshold));
    4455         275 :         CStakerStatus* ss = pwallet->pStakerStatus;
    4456         275 :         if (ss) {
    4457         275 :             obj.pushKV("lastattempt_age", (int)(GetTime() - ss->GetLastTime()));
    4458         537 :             obj.pushKV("lastattempt_depth", (chainActive.Height() - ss->GetLastHeight()));
    4459         825 :             obj.pushKV("lastattempt_hash", ss->GetLastHash().GetHex());
    4460         275 :             obj.pushKV("lastattempt_coins", ss->GetLastCoins());
    4461         550 :             obj.pushKV("lastattempt_tries", ss->GetLastTries());
    4462             :         }
    4463         275 :         return obj;
    4464             :     }
    4465             : }
    4466             : 
    4467           0 : UniValue setstakesplitthreshold(const JSONRPCRequest& request)
    4468             : {
    4469           0 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4470             : 
    4471           0 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4472           0 :         return NullUniValue;
    4473             : 
    4474           0 :     if (request.fHelp || request.params.size() != 1)
    4475           0 :         throw std::runtime_error(
    4476             :             "setstakesplitthreshold value\n\n"
    4477             :             "This will set the stake-split threshold value.\n"
    4478             :             "Whenever a successful stake is found, the stake amount is split across as many outputs (each with a value\n"
    4479             :             "higher than the threshold) as possible.\n"
    4480             :             "E.g. If the coinstake input + the block reward is 2000, and the split threshold is 499, the corresponding\n"
    4481             :             "coinstake transaction will have 4 outputs (of 500 PIV each)."
    4482           0 :             + HelpRequiringPassphrase(pwallet) + "\n"
    4483             : 
    4484             :             "\nArguments:\n"
    4485             :             "1. value                   (numeric, required) Threshold value (in PIV).\n"
    4486             :             "                                     Set to 0 to disable stake-splitting\n"
    4487           0 :             "                                     If > 0, it must be >= " + FormatMoney(CWallet::minStakeSplitThreshold) + "\n"
    4488             : 
    4489             :             "\nResult:\n"
    4490             :             "{\n"
    4491             :             "  \"threshold\": n,        (numeric) Threshold value set\n"
    4492             :             "  \"saved\": true|false    (boolean) 'true' if successfully saved to the wallet file\n"
    4493             :             "}\n"
    4494             : 
    4495           0 :             "\nExamples:\n" +
    4496           0 :             HelpExampleCli("setstakesplitthreshold", "500.12") + HelpExampleRpc("setstakesplitthreshold", "500.12"));
    4497             : 
    4498           0 :     CAmount nStakeSplitThreshold = AmountFromValue(request.params[0]);
    4499           0 :     if (nStakeSplitThreshold > 0 && nStakeSplitThreshold < CWallet::minStakeSplitThreshold)
    4500           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(_("The threshold value cannot be less than %s"),
    4501           0 :                 FormatMoney(CWallet::minStakeSplitThreshold)));
    4502             : 
    4503           0 :     UniValue result(UniValue::VOBJ);
    4504           0 :     result.pushKV("threshold", request.params[0]);
    4505           0 :     result.pushKV("saved", pwallet->SetStakeSplitThreshold(nStakeSplitThreshold));
    4506           0 :     return result;
    4507             : }
    4508             : 
    4509           0 : UniValue getstakesplitthreshold(const JSONRPCRequest& request)
    4510             : {
    4511           0 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4512             : 
    4513           0 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4514           0 :         return NullUniValue;
    4515             : 
    4516           0 :     if (request.fHelp || request.params.size() != 0)
    4517           0 :         throw std::runtime_error(
    4518             :             "getstakesplitthreshold\n"
    4519             :             "Returns the threshold for stake splitting\n"
    4520             : 
    4521             :             "\nResult:\n"
    4522             :             "n      (numeric) Threshold value\n"
    4523             : 
    4524           0 :             "\nExamples:\n" +
    4525           0 :             HelpExampleCli("getstakesplitthreshold", "") + HelpExampleRpc("getstakesplitthreshold", ""));
    4526             : 
    4527           0 :     return ValueFromAmount(pwallet->GetStakeSplitThreshold());
    4528             : }
    4529             : 
    4530           6 : UniValue setautocombinethreshold(const JSONRPCRequest& request)
    4531             : {
    4532           6 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4533             : 
    4534           6 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4535           0 :         return NullUniValue;
    4536             : 
    4537           6 :     if (request.fHelp || request.params.empty() || request.params.size() > 3)
    4538           0 :         throw std::runtime_error(
    4539             :             "setautocombinethreshold enable ( value )\n"
    4540             :             "\nThis will set the auto-combine threshold value.\n"
    4541             :             "\nWallet will automatically monitor for any coins with value below the threshold amount, and combine them if they reside with the same PIVX address\n"
    4542             :             "When auto-combine runs it will create a transaction, and therefore will be subject to transaction fees.\n"
    4543             : 
    4544             :             "\nArguments:\n"
    4545             :             "1. enable          (boolean, required) Enable auto combine (true) or disable (false).\n"
    4546             :             "2. threshold       (numeric, optional. required if enable is true) Threshold amount. Must be greater than 1.\n"
    4547             :             "3. frequency       (numeric, optional. default value is 30 if not provided). Check for UTXOs to autocombine each N blocks where N is the frequency.\n"
    4548             : 
    4549             :             "\nResult:\n"
    4550             :             "{\n"
    4551             :             "  \"enabled\": true|false,      (boolean) true if auto-combine is enabled, otherwise false\n"
    4552             :             "  \"threshold\": n.nnn,         (numeric) auto-combine threshold in PIV\n"
    4553             :             "  \"frequency\": n.nnn,         (numeric) auto-combine frequency in blocks\n"
    4554             :             "  \"saved\": true|false         (boolean) true if setting was saved to the database, otherwise false\n"
    4555             :             "}\n"
    4556             : 
    4557           0 :             "\nExamples:\n" +
    4558           0 :             HelpExampleCli("setautocombinethreshold", "true 500.12 40") + HelpExampleRpc("setautocombinethreshold", "true, 500.12, 40"));
    4559             : 
    4560           6 :     RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VNUM, UniValue::VNUM});
    4561             : 
    4562           6 :     bool fEnable = request.params[0].get_bool();
    4563           6 :     CAmount nThreshold = 0;
    4564           6 :     int frequency = 30;
    4565             : 
    4566           6 :     if (fEnable) {
    4567           5 :         if (request.params.size() < 2) {
    4568           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing threshold value");
    4569             :         }
    4570           4 :         nThreshold = AmountFromValue(request.params[1]);
    4571           4 :         if (nThreshold < COIN)
    4572           4 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("The threshold value cannot be less than %s", FormatMoney(COIN)));
    4573           2 :         if (request.params.size() == 3) {
    4574           2 :             frequency = request.params[2].get_int();
    4575           2 :             if (frequency <= 0) {
    4576           2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Frequency must be greater than 0"));
    4577             :             }
    4578             :         }
    4579             :     }
    4580             : 
    4581           4 :     WalletBatch batch(pwallet->GetDBHandle());
    4582             : 
    4583           2 :     {
    4584           4 :         LOCK(pwallet->cs_wallet);
    4585           2 :         pwallet->fCombineDust = fEnable;
    4586           2 :         pwallet->nAutoCombineThreshold = nThreshold;
    4587           2 :         pwallet->frequency = frequency;
    4588             : 
    4589           4 :         UniValue result(UniValue::VOBJ);
    4590           2 :         result.pushKV("enabled", fEnable);
    4591           4 :         result.pushKV("threshold", ValueFromAmount(pwallet->nAutoCombineThreshold));
    4592           2 :         result.pushKV("frequency", frequency);
    4593           2 :         if (batch.WriteAutoCombineSettings(fEnable, nThreshold, frequency)) {
    4594           4 :             result.pushKV("saved", "true");
    4595             :         } else {
    4596           0 :             result.pushKV("saved", "false");
    4597             :         }
    4598             : 
    4599           2 :         return result;
    4600             :     }
    4601             : }
    4602             : 
    4603           2 : UniValue getautocombinethreshold(const JSONRPCRequest& request)
    4604             : {
    4605           2 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4606             : 
    4607           2 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4608           0 :         return NullUniValue;
    4609             : 
    4610           2 :     if (request.fHelp || !request.params.empty())
    4611           0 :         throw std::runtime_error(
    4612             :             "getautocombinethreshold\n"
    4613             :             "\nReturns the current threshold and frequency for auto combining UTXOs, if any\n"
    4614             : 
    4615             :             "\nResult:\n"
    4616             :             "{\n"
    4617             :             "  \"enabled\": true|false,        (boolean) true if auto-combine is enabled, otherwise false\n"
    4618             :             "  \"threshold\": n.nnn            (numeric) the auto-combine threshold amount in PIV\n"
    4619             :             "  \"frequency\": n.nnn            (numeric) the auto-combine frequency in blocks\n"
    4620             :             "}\n"
    4621             : 
    4622           0 :             "\nExamples:\n" +
    4623           0 :             HelpExampleCli("getautocombinethreshold", "") + HelpExampleRpc("getautocombinethreshold", ""));
    4624             : 
    4625           4 :     LOCK(pwallet->cs_wallet);
    4626             : 
    4627           4 :     UniValue result(UniValue::VOBJ);
    4628           2 :     result.pushKV("enabled", pwallet->fCombineDust);
    4629           4 :     result.pushKV("threshold", ValueFromAmount(pwallet->nAutoCombineThreshold));
    4630           2 :     result.pushKV("frequency", pwallet->frequency);
    4631             : 
    4632           2 :     return result;
    4633             : }
    4634             : 
    4635           3 : UniValue getsaplingnotescount(const JSONRPCRequest& request)
    4636             : {
    4637           3 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4638             : 
    4639           3 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4640           0 :         return NullUniValue;
    4641             : 
    4642           3 :     if (request.fHelp || request.params.size() > 1)
    4643           0 :         throw std::runtime_error(
    4644             :                 "getsaplingnotescount ( minconf )\n"
    4645             :                 "Returns the number of sapling notes available in the wallet.\n"
    4646             : 
    4647             :                 "\nArguments:\n"
    4648             :                 "1. minconf      (numeric, optional, default=1) Only include notes in transactions confirmed at least this many times.\n"
    4649             : 
    4650             :                 "\nResult:\n"
    4651             :                 "num             (numeric) the number of sapling notes in the wallet\n"
    4652             : 
    4653             :                 "\nExamples:\n"
    4654           0 :                 + HelpExampleCli("getsaplingnotescount", "0")
    4655           0 :                 + HelpExampleRpc("getsaplingnotescount", "0")
    4656           0 :         );
    4657             : 
    4658             :     // Make sure the results are valid at least up to the most recent block
    4659             :     // the user could have gotten from another RPC command prior to now
    4660           3 :     pwallet->BlockUntilSyncedToCurrentChain();
    4661             : 
    4662           9 :     LOCK2(cs_main, pwallet->cs_wallet);
    4663             : 
    4664           3 :     int nMinDepth = !request.params.empty() ? request.params[0].get_int() : 1;
    4665           3 :     int count = 0;
    4666         160 :     for (const auto& wtx : pwallet->mapWallet) {
    4667         157 :         if (wtx.second.GetDepthInMainChain() >= nMinDepth) {
    4668         162 :             for (const auto& nd : wtx.second.mapSaplingNoteData) {
    4669           6 :                 if (nd.second.IsMyNote()) count++;
    4670             :             }
    4671             :         }
    4672             :     }
    4673           3 :     return count;
    4674             : }
    4675             : 
    4676           2 : UniValue rescanblockchain(const JSONRPCRequest& request)
    4677             : {
    4678           2 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4679             : 
    4680           2 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4681           0 :         return NullUniValue;
    4682             : 
    4683           2 :     if (request.fHelp || request.params.size() > 2) {
    4684           0 :         throw std::runtime_error(
    4685             :                 "rescanblockchain (start_height) (stop_height)\n"
    4686             :                 "\nRescan the local blockchain for wallet related transactions.\n"
    4687             :                 "\nArguments:\n"
    4688             :                 "1. start_height    (numeric, optional) block height where the rescan should start\n"
    4689             :                 "2. stop_height     (numeric, optional) the last block height that should be scanned\n"
    4690             :                 "\nResult:\n"
    4691             :                 "{\n"
    4692             :                 "  start_height     (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
    4693             :                 "  stop_height      (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
    4694             :                 "}\n"
    4695             :                 "\nExamples:\n"
    4696           0 :                 + HelpExampleCli("rescanblockchain", "100000 120000")
    4697           0 :                 + HelpExampleRpc("rescanblockchain", "100000 120000")
    4698           0 :         );
    4699             :     }
    4700             : 
    4701           4 :     WalletRescanReserver reserver(pwallet);
    4702           2 :     if (!reserver.reserve()) {
    4703           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
    4704             :     }
    4705             : 
    4706           2 :     CBlockIndex *pindexStart = nullptr;
    4707           2 :     CBlockIndex *pindexStop = nullptr;
    4708           2 :     CBlockIndex *pChainTip = nullptr;
    4709           2 :     {
    4710           2 :         LOCK(cs_main);
    4711           2 :         pindexStart = chainActive.Genesis();
    4712           2 :         pChainTip = chainActive.Tip();
    4713             : 
    4714           2 :         if (!request.params[0].isNull()) {
    4715           1 :             pindexStart = chainActive[request.params[0].get_int()];
    4716           1 :             if (!pindexStart) {
    4717           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
    4718             :             }
    4719             :         }
    4720             : 
    4721           2 :         if (!request.params[1].isNull()) {
    4722           1 :             pindexStop = chainActive[request.params[1].get_int()];
    4723           1 :             if (!pindexStop) {
    4724           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
    4725             :             }
    4726           1 :             else if (pindexStop->nHeight < pindexStart->nHeight) {
    4727           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater then start_height");
    4728             :             }
    4729             :         }
    4730             :     }
    4731             : 
    4732           2 :     CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true);
    4733           2 :     if (!stopBlock) {
    4734           2 :         if (pwallet->IsAbortingRescan()) {
    4735           0 :             throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
    4736             :         }
    4737             :         // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
    4738           2 :         stopBlock = pindexStop ? pindexStop : pChainTip;
    4739             :     }
    4740             :     else {
    4741           0 :         throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
    4742             :     }
    4743             : 
    4744           4 :     UniValue response(UniValue::VOBJ);
    4745           2 :     response.pushKV("start_height", pindexStart->nHeight);
    4746           2 :     response.pushKV("stop_height", stopBlock->nHeight);
    4747           2 :     return response;
    4748             : }
    4749             : 
    4750             : extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
    4751             : extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
    4752             : extern UniValue importprivkey(const JSONRPCRequest& request);
    4753             : extern UniValue importaddress(const JSONRPCRequest& request);
    4754             : extern UniValue importpubkey(const JSONRPCRequest& request);
    4755             : extern UniValue dumpwallet(const JSONRPCRequest& request);
    4756             : extern UniValue importwallet(const JSONRPCRequest& request);
    4757             : extern UniValue importmulti(const JSONRPCRequest& request);
    4758             : extern UniValue bip38encrypt(const JSONRPCRequest& request);
    4759             : extern UniValue bip38decrypt(const JSONRPCRequest& request);
    4760             : 
    4761             : extern UniValue exportsaplingkey(const JSONRPCRequest& request);
    4762             : extern UniValue importsaplingkey(const JSONRPCRequest& request);
    4763             : extern UniValue importsaplingviewingkey(const JSONRPCRequest& request);
    4764             : extern UniValue exportsaplingviewingkey(const JSONRPCRequest& request);
    4765             : 
    4766             : // clang-format off
    4767             : static const CRPCCommand commands[] =
    4768             : { //  category              name                        actor (function)           okSafe argNames
    4769             :   //  --------------------- ------------------------    -----------------------    ------ --------
    4770             :     { "wallet",             "getaddressinfo",           &getaddressinfo,           true,  {"address"} },
    4771             :     { "wallet",             "setautocombinethreshold",  &setautocombinethreshold,  false, {"enable","threshold"} },
    4772             :     { "wallet",             "getautocombinethreshold",  &getautocombinethreshold,  false, {} },
    4773             :     { "wallet",             "abandontransaction",       &abandontransaction,       false, {"txid"} },
    4774             :     { "wallet",             "abortrescan",              &abortrescan,              false, {} },
    4775             :     { "wallet",             "addmultisigaddress",       &addmultisigaddress,       true,  {"nrequired","keys","label"} },
    4776             :     { "wallet",             "backupwallet",             &backupwallet,             true,  {"destination"} },
    4777             :     { "wallet",             "delegatestake",            &delegatestake,            false, {"staking_addr","amount","owner_addr","ext_owner","include_delegated","from_shield","force"} },
    4778             :     { "wallet",             "dumpprivkey",              &dumpprivkey,              true,  {"address"} },
    4779             :     { "wallet",             "dumpwallet",               &dumpwallet,               true,  {"filename"} },
    4780             :     { "wallet",             "encryptwallet",            &encryptwallet,            true,  {"passphrase"} },
    4781             :     { "wallet",             "fundrawtransaction",       &fundrawtransaction,       false, {"hexstring","options"} },
    4782             :     { "wallet",             "getbalance",               &getbalance,               false, {"minconf","include_watchonly","include_delegated","include_shield"} },
    4783             :     { "wallet",             "getcoldstakingbalance",    &getcoldstakingbalance,    false, {} },
    4784             :     { "wallet",             "getdelegatedbalance",      &getdelegatedbalance,      false, {} },
    4785             :     { "wallet",             "upgradewallet",            &upgradewallet,            true,  {} },
    4786             :     { "wallet",             "sethdseed",                &sethdseed,                true,  {"newkeypool","seed"} },
    4787             :     { "wallet",             "getnewaddress",            &getnewaddress,            true,  {"label"} },
    4788             :     { "wallet",             "getnewexchangeaddress",    &getnewexchangeaddress,    true,  {"label"} },
    4789             :     { "wallet",             "getnewstakingaddress",     &getnewstakingaddress,     true,  {"label"}  },
    4790             :     { "wallet",             "getrawchangeaddress",      &getrawchangeaddress,      true,  {} },
    4791             :     { "wallet",             "getreceivedbyaddress",     &getreceivedbyaddress,     false, {"address","minconf"} },
    4792             :     { "wallet",             "gettransaction",           &gettransaction,           false, {"txid","include_watchonly"} },
    4793             :     { "wallet",             "getstakesplitthreshold",   &getstakesplitthreshold,   false, {} },
    4794             :     { "wallet",             "getunconfirmedbalance",    &getunconfirmedbalance,    false, {} },
    4795             :     { "wallet",             "getwalletinfo",            &getwalletinfo,            false, {} },
    4796             :     { "wallet",             "getstakingstatus",         &getstakingstatus,         false, {} },
    4797             :     { "wallet",             "importprivkey",            &importprivkey,            true,  {"privkey","label","rescan","is_staking_address"} },
    4798             :     { "wallet",             "importwallet",             &importwallet,             true,  {"filename"} },
    4799             :     { "wallet",             "importaddress",            &importaddress,            true,  {"address","label","rescan","p2sh"} },
    4800             :     { "wallet",             "importpubkey",             &importpubkey,             true,  {"pubkey","label","rescan"} },
    4801             :     { "wallet",             "importmulti",              &importmulti,              true,  {"requests","options"} },
    4802             :     { "wallet",             "keypoolrefill",            &keypoolrefill,            true,  {"newsize"} },
    4803             :     { "wallet",             "listaddressgroupings",     &listaddressgroupings,     false, {} },
    4804             :     { "wallet",             "listdelegators",           &listdelegators,           false, {"blacklist"} },
    4805             :     { "wallet",             "liststakingaddresses",     &liststakingaddresses,     false, {} },
    4806             :     { "wallet",             "listcoldutxos",            &listcoldutxos,            false, {"not_whitelisted"} },
    4807             :     { "wallet",             "listlockunspent",          &listlockunspent,          false, {} },
    4808             :     { "wallet",             "listreceivedbyaddress",    &listreceivedbyaddress,    false, {"minconf","include_empty","include_watchonly","filter"} },
    4809             :     { "wallet",             "listsinceblock",           &listsinceblock,           false, {"blockhash","target_confirmations","include_watchonly"} },
    4810             :     { "wallet",             "listtransactions",         &listtransactions,         false, {"dummy","count","from","include_watchonly","include_delegated","include_cold"} },
    4811             :     { "wallet",             "listunspent",              &listunspent,              false, {"minconf","maxconf","addresses","watchonly_config","query_options","include_unsafe" } },
    4812             :     { "wallet",             "listwallets",              &listwallets,              true,  {} },
    4813             :     { "wallet",             "lockunspent",              &lockunspent,              true,  {"unlock", "transparent", "transactions"} },
    4814             :     { "wallet",             "rawdelegatestake",         &rawdelegatestake,         false, {"staking_addr","amount","owner_addr","ext_owner","include_delegated","from_shield","force"} },
    4815             :     { "wallet",             "sendmany",                 &sendmany,                 false, {"dummy","amounts","minconf","comment","include_delegated","subtract_fee_from"} },
    4816             :     { "wallet",             "sendtoaddress",            &sendtoaddress,            false, {"address","amount","comment","comment-to","subtract_fee"} },
    4817             :     { "wallet",             "settxfee",                 &settxfee,                 true,  {"amount"} },
    4818             :     { "wallet",             "setstakesplitthreshold",   &setstakesplitthreshold,   false, {"value"} },
    4819             :     { "wallet",             "signmessage",              &signmessage,              true,  {"address","message"} },
    4820             :     { "wallet",             "walletlock",               &walletlock,               true,  {} },
    4821             :     { "wallet",             "walletpassphrasechange",   &walletpassphrasechange,   true,  {"oldpassphrase","newpassphrase"} },
    4822             :     { "wallet",             "walletpassphrase",         &walletpassphrase,         true,  {"passphrase","timeout","staking_only"} },
    4823             :     { "wallet",             "rescanblockchain",         &rescanblockchain,         true,  {"start_height","stop_height"} },
    4824             :     { "wallet",             "delegatoradd",             &delegatoradd,             true,  {"address","label"} },
    4825             :     { "wallet",             "delegatorremove",          &delegatorremove,          true,  {"address"} },
    4826             :     { "wallet",             "bip38encrypt",             &bip38encrypt,             true,  {"address","passphrase"} },
    4827             :     { "wallet",             "bip38decrypt",             &bip38decrypt,             true,  {"encrypted_key","passphrase"} },
    4828             : 
    4829             :     /** Sapling functions */
    4830             :     { "wallet",             "getnewshieldaddress",           &getnewshieldaddress,            true,  {"label"} },
    4831             :     { "wallet",             "listshieldaddresses",           &listshieldaddresses,            false, {"include_watchonly"} },
    4832             :     { "wallet",             "exportsaplingkey",              &exportsaplingkey,               true,  {"shield_addr"} },
    4833             :     { "wallet",             "importsaplingkey",              &importsaplingkey,               true,  {"key","rescan","height"} },
    4834             :     { "wallet",             "importsaplingviewingkey",       &importsaplingviewingkey,        true,  {"vkey","rescan","height"}  },
    4835             :     { "wallet",             "exportsaplingviewingkey",       &exportsaplingviewingkey,        true,  {"shield_addr"} },
    4836             :     { "wallet",             "getshieldbalance",              &getshieldbalance,               false, {"address","minconf","include_watchonly"} },
    4837             :     { "wallet",             "listshieldunspent",             &listshieldunspent,              false, {"minconf","maxconf","include_watchonly","addresses"} },
    4838             :     { "wallet",             "rawshieldsendmany",             &rawshieldsendmany,              false, {"fromaddress","amounts","minconf","fee"} },
    4839             :     { "wallet",             "shieldsendmany",                &shieldsendmany,                 false, {"fromaddress","amounts","minconf","fee","subtract_fee_from"} },
    4840             :     { "wallet",             "listreceivedbyshieldaddress",   &listreceivedbyshieldaddress,    false, {"address","minconf"} },
    4841             :     { "wallet",             "viewshieldtransaction",         &viewshieldtransaction,          false, {"txid"} },
    4842             :     { "wallet",             "getsaplingnotescount",          &getsaplingnotescount,           false, {"minconf"} },
    4843             : 
    4844             :     /** Label functions (to replace non-balance account functions) */
    4845             :     { "wallet",             "getaddressesbylabel",      &getaddressesbylabel,      true,  {"label"} },
    4846             :     { "wallet",             "getreceivedbylabel",       &getreceivedbylabel,       false, {"label","minconf"} },
    4847             :     { "wallet",             "listlabels",               &listlabels,               false, {"purpose"} },
    4848             :     { "wallet",             "listreceivedbylabel",      &listreceivedbylabel,      false, {"minconf","include_empty","include_watchonly"} },
    4849             :     { "wallet",             "setlabel",                 &setlabel,                 true,  {"address","label"} },
    4850             : };
    4851             : // clang-format on
    4852             : 
    4853         350 : void RegisterWalletRPCCommands(CRPCTable &tableRPC)
    4854             : {
    4855         350 :     if (gArgs.GetBoolArg("-disablewallet", false)) {
    4856             :         return;
    4857             :     }
    4858       26103 :     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) {
    4859       25764 :         tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
    4860             :     }
    4861             : }

Generated by: LCOV version 1.14