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: 2025-02-23 09:33:43 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      115699 : CWallet* GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
      40             : {
      41      115699 :     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      115671 :     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       11677 : bool EnsureWalletIsAvailable(CWallet* const pwallet, bool avoidException)
      60             : {
      61       11677 :     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      107395 : void EnsureWalletIsUnlocked(CWallet* const pwallet, bool fAllowAnonOnly)
      72             : {
      73      107395 :     if (pwallet->IsLocked() || (!fAllowAnonOnly && pwallet->fWalletUnlockStaking))
      74          10 :         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
      75      107390 : }
      76             : 
      77         393 : static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
      78             : {
      79         393 :     AssertLockHeld(cs_main);
      80             : 
      81         393 :     int confirms = wtx.GetDepthInMainChain();
      82         393 :     entry.pushKV("confirmations", confirms);
      83         393 :     entry.pushKV("bcconfirmations", confirms);      // DEPRECATED in 4.3.99
      84         576 :     if (wtx.IsCoinBase() || wtx.IsCoinStake())
      85         420 :         entry.pushKV("generated", true);
      86         393 :     if (confirms > 0) {
      87         638 :         entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
      88         319 :         entry.pushKV("blockindex", wtx.m_confirm.nIndex);
      89         319 :         entry.pushKV("blocktime", LookupBlockIndex(wtx.m_confirm.hashBlock)->GetBlockTime());
      90             :     } else {
      91         148 :         entry.pushKV("trusted", wtx.IsTrusted());
      92             :     }
      93         393 :     uint256 hash = wtx.GetHash();
      94         786 :     entry.pushKV("txid", hash.GetHex());
      95         786 :     UniValue conflicts(UniValue::VARR);
      96         402 :     for (const uint256& conflict : wtx.GetConflicts())
      97          18 :         conflicts.push_back(conflict.GetHex());
      98         393 :     entry.pushKV("walletconflicts", conflicts);
      99         393 :     entry.pushKV("time", wtx.GetTxTime());
     100         393 :     entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
     101         410 :     for (const std::pair<std::string, std::string> & item : wtx.mapValue)
     102          17 :         entry.pushKV(item.first, item.second);
     103         393 : }
     104             : 
     105         355 : std::string LabelFromValue(const UniValue& value)
     106             : {
     107         355 :     std::string label = value.get_str();
     108         355 :     if (label == "*")
     109           0 :         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
     110         355 :     return label;
     111             : }
     112             : 
     113        2279 : static CTxDestination GetNewAddressFromLabel(CWallet* const pwallet, const std::string purpose, const UniValue &params,
     114             :                                              const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS)
     115             : {
     116        4558 :     LOCK2(cs_main, pwallet->cs_wallet);
     117             :     // Parse the label first so we don't generate a key if there's an error
     118        4558 :     std::string label;
     119        2279 :     if (!params.isNull() && params.size() > 0)
     120         257 :         label = LabelFromValue(params[0]);
     121             : 
     122        6840 :     auto r = pwallet->getNewAddress(label, purpose, addrType);
     123        2279 :     if(!r)
     124           6 :         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, r.getError());
     125        4552 :     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        2255 : UniValue getnewaddress(const JSONRPCRequest& request)
     506             : {
     507        2255 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     508             : 
     509        2255 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     510           0 :         return NullUniValue;
     511             : 
     512        2255 :     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        4507 :     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         236 : UniValue getnewshieldaddress(const JSONRPCRequest& request)
     585             : {
     586         236 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     587             : 
     588         236 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     589           0 :         return NullUniValue;
     590             : 
     591         236 :     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         469 :     std::string label;
     611         235 :     if (!request.params.empty()) {
     612           0 :         label = LabelFromValue(request.params[0]);
     613             :     }
     614             : 
     615         705 :     LOCK2(cs_main, pwallet->cs_wallet);
     616             : 
     617         235 :     EnsureWalletIsUnlocked(pwallet);
     618             : 
     619         703 :     return KeyIO::EncodePaymentAddress(pwallet->GenerateNewSaplingZKey(label));
     620             : }
     621             : 
     622         379 : static inline std::string HexStrTrimmed(std::array<unsigned char, ZC_MEMO_SIZE> vch)
     623             : {
     624         758 :     return HexStr(std::vector<unsigned char>(vch.begin(), FindFirstNonZero(vch.rbegin(), vch.rend()).base()));
     625             : }
     626             : 
     627          18 : UniValue listshieldunspent(const JSONRPCRequest& request)
     628             : {
     629          18 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     630             : 
     631          18 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     632           0 :         return NullUniValue;
     633             : 
     634          18 :     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          17 :     RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VBOOL, UniValue::VARR});
     674             : 
     675          17 :     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          16 :     int nMaxDepth = request.params.size() > 1 ? request.params[1].get_int() : 9999999;
     681          15 :     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          25 :     std::set<libzcash::PaymentAddress> shieldAddrs = {};
     686          14 :     bool fIncludeWatchonly = request.params.size() > 2 && request.params[2].get_bool();
     687             : 
     688          42 :     LOCK2(cs_main, pwallet->cs_wallet);
     689             : 
     690             :     // User has supplied shield addrs to filter on
     691          14 :     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          18 :         std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
     724           9 :         pwallet->GetSaplingPaymentAddresses(saplingzaddrs);
     725           9 :         shieldAddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
     726             :     }
     727             : 
     728          22 :     UniValue results(UniValue::VARR);
     729             : 
     730          11 :     if (shieldAddrs.size() > 0) {
     731          22 :         std::vector<SaplingNoteEntry> saplingEntries;
     732          11 :         pwallet->GetSaplingScriptPubKeyMan()->GetFilteredNotes(saplingEntries, shieldAddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
     733          22 :         std::set<std::pair<libzcash::PaymentAddress, uint256>> nullifierSet = pwallet->GetSaplingScriptPubKeyMan()->GetNullifiersForAddresses(shieldAddrs);
     734             : 
     735         349 :         for (const auto& entry : saplingEntries) {
     736         676 :             UniValue obj(UniValue::VOBJ);
     737         676 :             obj.pushKV("txid", entry.op.hash.ToString());
     738         338 :             obj.pushKV("outindex", (int)entry.op.n);
     739         338 :             obj.pushKV("confirmations", entry.confirmations);
     740         338 :             bool hasSaplingSpendingKey = pwallet->HaveSpendingKeyForPaymentAddress(entry.address);
     741         338 :             obj.pushKV("spendable", hasSaplingSpendingKey);
     742        1014 :             obj.pushKV("address", KeyIO::EncodePaymentAddress(entry.address));
     743         676 :             obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
     744         676 :             obj.pushKV("memo", HexStrTrimmed(entry.memo));
     745         338 :             if (hasSaplingSpendingKey) {
     746         676 :                 obj.pushKV("change", pwallet->GetSaplingScriptPubKeyMan()->IsNoteSaplingChange(nullifierSet, entry.address, entry.op));
     747             :             }
     748         338 :             const auto& nd = pwallet->mapWallet.at(entry.op.hash).mapSaplingNoteData.at(entry.op);
     749         338 :             if (nd.nullifier) {
     750        1014 :                 obj.pushKV("nullifier", nd.nullifier->ToString());
     751             :             }
     752         338 :             results.push_back(obj);
     753             :         }
     754             :     }
     755             : 
     756          11 :     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         304 : static void SendMoney(CWallet* const pwallet, const CTxDestination& address, CAmount nValue, bool fSubtractFeeFromAmount, CTransactionRef& tx)
    1056             : {
    1057         608 :     LOCK2(cs_main, pwallet->cs_wallet);
    1058             : 
    1059             :     // Check amount
    1060         304 :     if (nValue <= 0)
    1061           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
    1062             : 
    1063         304 :     if (nValue > pwallet->GetAvailableBalance())
    1064           0 :         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
    1065             : 
    1066         304 :     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         608 :     CScript scriptPubKey = GetScriptForDestination(address);
    1071             : 
    1072             :     // Create and send the transaction
    1073         608 :     CReserveKey reservekey(pwallet);
    1074         304 :     CAmount nFeeRequired;
    1075         608 :     std::string strError;
    1076         608 :     std::vector<CRecipient> vecSend;
    1077         304 :     int nChangePosRet = -1;
    1078         608 :     CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
    1079         304 :     vecSend.push_back(recipient);
    1080         304 :     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         607 :     const CWallet::CommitResult&& res = pwallet->CommitTransaction(tx, reservekey, g_connman.get());
    1087         303 :     if (res.status != CWallet::CommitStatus::OK)
    1088           0 :         throw JSONRPCError(RPC_WALLET_ERROR, res.ToString());
    1089         303 : }
    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         320 : UniValue sendtoaddress(const JSONRPCRequest& request)
    1146             : {
    1147         320 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1148             : 
    1149         320 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1150           0 :         return NullUniValue;
    1151             : 
    1152         320 :     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         320 :     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         319 :     pwallet->BlockUntilSyncedToCurrentChain();
    1183             : 
    1184         319 :     bool isStaking = false, isExchange = false, isShielded = false;
    1185         637 :     const std::string addrStr = request.params[0].get_str();
    1186         638 :     const CWDestination& destination = Standard::DecodeDestination(addrStr, isStaking, isExchange, isShielded);
    1187         319 :     if (!Standard::IsValidDestination(destination) || isStaking)
    1188           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
    1189         319 :     const std::string commentStr = (request.params.size() > 2 && !request.params[2].isNull()) ?
    1190         642 :                                    request.params[2].get_str() : "";
    1191         319 :     const std::string toStr = (request.params.size() > 3 && !request.params[3].isNull()) ?
    1192         642 :                                    request.params[3].get_str() : "";
    1193         319 :     bool fSubtractFeeFromAmount = request.params.size() > 4 && request.params[4].get_bool();
    1194             : 
    1195         319 :     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         304 :     const CTxDestination& address = *Standard::GetTransparentDestination(destination);
    1206             : 
    1207             :     // Amount
    1208         304 :     CAmount nAmount = AmountFromValue(request.params[1]);
    1209             : 
    1210         319 :     CTransactionRef tx;
    1211         304 :     SendMoney(pwallet, address, nAmount, fSubtractFeeFromAmount, tx);
    1212             : 
    1213             :     // Wallet comments
    1214         303 :     CWalletTx& wtx = pwallet->mapWallet.at(tx->GetHash());
    1215         303 :     if (!commentStr.empty())
    1216           0 :         wtx.mapValue["comment"] = commentStr;
    1217         303 :     if (!toStr.empty())
    1218           0 :         wtx.mapValue["to"] = toStr;
    1219             : 
    1220         607 :     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        1088 : static SaplingOperation CreateShieldedTransaction(CWallet* const pwallet, const JSONRPCRequest& request)
    1691             : {
    1692        2176 :     LOCK2(cs_main, pwallet->cs_wallet);
    1693        1088 :     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        1088 :     bool fromSapling  = false;
    1698        2176 :     std::string sendFromStr = request.params[0].get_str();
    1699        1088 :     if (sendFromStr == "from_transparent") {
    1700             :         // send from any transparent address
    1701        1035 :         operation.setSelectTransparentCoins(true);
    1702          53 :     } else if (sendFromStr == "from_trans_cold") {
    1703             :         // send from any transparent address + delegations
    1704           0 :         operation.setSelectTransparentCoins(true, true);
    1705          53 :     } else if (sendFromStr == "from_shield") {
    1706             :         // send from any shield address
    1707          12 :         operation.setSelectShieldedCoins(true);
    1708          12 :         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        2172 :     const UniValue subtractFeeFromAmount = request.params[4];
    1731             : 
    1732             :     // Param 1: array of outputs
    1733        1092 :     UniValue outputs = request.params[1].get_array();
    1734        1086 :     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        2170 :     std::set<std::string> setAddress;
    1739             :     // Recipients
    1740        2170 :     std::vector<SendManyRecipient> recipients;
    1741        1085 :     CAmount nTotalOut = 0;
    1742        1085 :     bool containsSaplingOutput = false;
    1743             : 
    1744        2238 :     for (const UniValue& o : outputs.getValues()) {
    1745        1153 :         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        3463 :         for (const std::string& name_ : o.getKeys()) {
    1750        3471 :             if (name_ != "address" && name_ != "amount" && name_!="memo")
    1751           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, unknown key: ")+name_);
    1752             :         }
    1753             : 
    1754        3459 :         std::string address = find_value(o, "address").get_str();
    1755        2306 :         CTxDestination taddr = DecodeDestination(address);
    1756        2306 :         Optional<libzcash::SaplingPaymentAddress> saddr;
    1757             : 
    1758        1153 :         if (!IsValidDestination(taddr)) {
    1759        2262 :             const auto& addr = KeyIO::DecodePaymentAddress(address);
    1760        1131 :             if (IsValidPaymentAddress(addr)) {
    1761        1131 :                 saddr = *(boost::get<libzcash::SaplingPaymentAddress>(&addr));
    1762        1131 :                 containsSaplingOutput = true;
    1763             :             } else {
    1764           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, unknown address format: ")+address );
    1765             :             }
    1766             :         }
    1767             : 
    1768        1153 :         if (setAddress.count(address))
    1769           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+address);
    1770        1153 :         setAddress.insert(address);
    1771             : 
    1772        2306 :         UniValue memoValue = find_value(o, "memo");
    1773        2306 :         std::string memo;
    1774        1153 :         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        2306 :         UniValue av = find_value(o, "amount");
    1785        1153 :         CAmount nAmount = AmountFromValue(av);
    1786        1153 :         if (nAmount < 0)
    1787           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
    1788             : 
    1789        1153 :         bool fSubtractFeeFromAmount = false;
    1790        1155 :         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        1153 :         if (saddr) {
    1799        1131 :             recipients.emplace_back(*saddr, nAmount, memo, fSubtractFeeFromAmount);
    1800             :         } else {
    1801          22 :             recipients.emplace_back(taddr, nAmount, fSubtractFeeFromAmount);
    1802             :         }
    1803             : 
    1804        1153 :         nTotalOut += nAmount;
    1805             :     }
    1806             : 
    1807             :     // Check network status
    1808        1085 :     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        2168 :     auto opResult = CheckTransactionSize(recipients, !fromSapling);
    1817        1084 :     if (!opResult) {
    1818           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, opResult.getError());
    1819             :     }
    1820             : 
    1821             :     // Param 2: Minimum confirmations
    1822        1084 :     int nMinDepth = request.params.size() > 2 ? request.params[2].get_int() : 1;
    1823          72 :     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        1084 :     if (request.params.size() > 3) {
    1830          51 :         CAmount nFee = AmountFromValue(request.params[3]);
    1831          51 :         if (nFee < 0) {
    1832           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid fee. Must be positive.");
    1833          51 :         } else if (nFee > 0) {
    1834             :             // If the user-selected fee is not enough (or too much), the build operation will fail.
    1835          32 :             operation.setFee(nFee);
    1836             :         }
    1837             :         // If nFee=0 leave the default (build operation will compute the minimum fee)
    1838             :     }
    1839             : 
    1840        1084 :     if (fromSapling && nMinDepth == 0) {
    1841           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be zero when sending from shield addr");
    1842             :     }
    1843             : 
    1844        1084 :     if (nMinDepth < 0) {
    1845           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be negative");
    1846             :     }
    1847             : 
    1848             :     // Build the send operation
    1849        1084 :     OperationResult res = operation.setMinDepth(nMinDepth)
    1850             :             ->setRecipients(recipients)
    1851        2168 :             ->build();
    1852        1088 :     if (!res) throw JSONRPCError(RPC_WALLET_ERROR, res.getError());
    1853        2160 :     return operation;
    1854             : }
    1855             : 
    1856        1055 : UniValue shieldsendmany(const JSONRPCRequest& request)
    1857             : {
    1858        1055 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1859             : 
    1860        1055 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1861           0 :         return NullUniValue;
    1862             : 
    1863        1055 :     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        1053 :     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        1053 :     pwallet->BlockUntilSyncedToCurrentChain();
    1909             : 
    1910        1054 :     SaplingOperation operation = CreateShieldedTransaction(pwallet, request);
    1911        2094 :     std::string txHash;
    1912        2094 :     auto res = operation.send(txHash);
    1913        1047 :     if (!res)
    1914           2 :         throw JSONRPCError(RPC_WALLET_ERROR, res.getError());
    1915        1046 :     return txHash;
    1916             : }
    1917             : 
    1918          18 : UniValue rawshieldsendmany(const JSONRPCRequest& request)
    1919             : {
    1920          18 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    1921             : 
    1922          18 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    1923           0 :         return NullUniValue;
    1924             : 
    1925          18 :     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          18 :     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          18 :     pwallet->BlockUntilSyncedToCurrentChain();
    1965             : 
    1966          34 :     CTransaction tx = CreateShieldedTransaction(pwallet, request).getFinalTx();
    1967          32 :     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          18 : UniValue signmessage(const JSONRPCRequest& request)
    2026             : {
    2027          18 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2028             : 
    2029          18 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2030           0 :         return NullUniValue;
    2031             : 
    2032          18 :     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          54 :     LOCK2(cs_main, pwallet->cs_wallet);
    2056             : 
    2057          18 :     EnsureWalletIsUnlocked(pwallet);
    2058             : 
    2059          36 :     std::string strAddress = request.params[0].get_str();
    2060          36 :     std::string strMessage = request.params[1].get_str();
    2061             : 
    2062          36 :     CTxDestination dest = DecodeDestination(strAddress);
    2063          18 :     if (!IsValidDestination(dest))
    2064           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
    2065             : 
    2066          18 :     const CKeyID* keyID = boost::get<CKeyID>(&dest);
    2067          18 :     if (!keyID)
    2068           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
    2069             : 
    2070          36 :     CKey key;
    2071          18 :     if (!pwallet->GetKey(*keyID, key))
    2072           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
    2073             : 
    2074          36 :     std::vector<unsigned char> vchSig;
    2075          18 :     if (!CMessageSigner::SignMessage(strMessage, vchSig, key)) {
    2076           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
    2077             :     }
    2078             : 
    2079          36 :     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         641 :     tallyitem()
    2570           5 :     {
    2571         641 :         nAmount = 0;
    2572         641 :         nConf = std::numeric_limits<int>::max();
    2573           5 :         fIsWatchonly = false;
    2574             :     }
    2575             : };
    2576             : 
    2577          79 : static UniValue ListReceived(CWallet* const pwallet, const UniValue& params, bool by_label, int nBlockHeight)
    2578             : {
    2579             :     // Minimum confirmations
    2580          79 :     int nMinDepth = 1;
    2581          79 :     if (params.size() > 0)
    2582          74 :         nMinDepth = params[0].get_int();
    2583             : 
    2584             :     // Whether to include empty labels
    2585          79 :     bool fIncludeEmpty = false;
    2586          79 :     if (params.size() > 1)
    2587          72 :         fIncludeEmpty = params[1].get_bool();
    2588             : 
    2589          79 :     isminefilter filter = ISMINE_SPENDABLE_ALL;
    2590          79 :     if (params.size() > 2)
    2591          70 :         if (params[2].get_bool())
    2592          44 :             filter = filter | ISMINE_WATCH_ONLY;
    2593             : 
    2594          79 :     bool has_filtered_address = false;
    2595          79 :     CTxDestination filtered_address = CNoDestination();
    2596          79 :     if (!by_label && params.size() > 3) {
    2597         136 :         CTxDestination dest = DecodeDestination(params[3].get_str());
    2598          68 :         if (!IsValidDestination(dest)) {
    2599           2 :             throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
    2600             :         }
    2601          67 :         filtered_address = dest;
    2602          67 :         has_filtered_address = true;
    2603             :     }
    2604             : 
    2605             :     // Tally
    2606         156 :     std::map<CTxDestination, tallyitem> mapTally;
    2607        4966 :     for (const auto& entry : pwallet->mapWallet) {
    2608        4888 :         const CWalletTx& wtx = entry.second;
    2609             : 
    2610        4888 :         if (!IsFinalTx(wtx.tx, nBlockHeight)) {
    2611          17 :             continue;
    2612             :         }
    2613             : 
    2614        4888 :         int nDepth = wtx.GetDepthInMainChain();
    2615        4888 :         if (nDepth < nMinDepth) {
    2616          17 :             continue;
    2617             :         }
    2618             : 
    2619       11572 :         for (const CTxOut& txout : wtx.tx->vout) {
    2620        7627 :             CTxDestination address;
    2621        6701 :             if (!ExtractDestination(txout.scriptPubKey, address)) {
    2622        5837 :                 continue;
    2623             :             }
    2624             : 
    2625        6639 :             if (has_filtered_address && !(filtered_address == address)) {
    2626        5693 :                 continue;
    2627             :             }
    2628             : 
    2629         946 :             isminefilter mine = IsMine(*pwallet, address);
    2630         946 :             if (!(mine & filter)) {
    2631          20 :                 continue;
    2632             :             }
    2633             : 
    2634         926 :             tallyitem& item = mapTally[address];
    2635         926 :             item.nAmount += txout.nValue;
    2636         926 :             item.nConf = std::min(item.nConf, nDepth);
    2637         926 :             item.txids.push_back(wtx.GetHash());
    2638         926 :             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          78 :     auto itAddr = pwallet->NewAddressBookIterator();
    2646             :     // If we are filtering, find() the applicable entry
    2647          78 :     if (has_filtered_address) {
    2648          67 :         itAddr.SetFilter(filtered_address);
    2649             :     }
    2650             : 
    2651             :     // Reply
    2652          78 :     UniValue ret(UniValue::VARR);
    2653         156 :     std::map<std::string, tallyitem> label_tally;
    2654             : 
    2655         350 :     for (auto& itAddrBook = itAddr; itAddrBook.IsValid(); itAddrBook.Next()) {
    2656             : 
    2657          97 :         auto* dest = itAddrBook.GetCTxDestKey();
    2658         105 :         if (!dest) continue;
    2659             : 
    2660          97 :         const auto &address = *dest;
    2661         186 :         const std::string &label = itAddrBook.GetValue().name;
    2662          97 :         auto it = mapTally.find(address);
    2663          97 :         if (it == mapTally.end() && !fIncludeEmpty) {
    2664           8 :             continue;
    2665             :         }
    2666             : 
    2667          89 :         CAmount nAmount = 0;
    2668          89 :         int nConf = std::numeric_limits<int>::max();
    2669          89 :         bool fIsWatchonly = false;
    2670          89 :         if (it != mapTally.end()) {
    2671          71 :             nAmount = (*it).second.nAmount;
    2672          71 :             nConf = (*it).second.nConf;
    2673          71 :             fIsWatchonly = (*it).second.fIsWatchonly;
    2674             :         }
    2675             : 
    2676          89 :         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         148 :             UniValue obj(UniValue::VOBJ);
    2683          74 :             if (fIsWatchonly)
    2684          32 :                 obj.pushKV("involvesWatchonly", true);
    2685         148 :             obj.pushKV("address", EncodeDestination(address, AddressBook::IsColdStakingPurpose(label), AddressBook::IsExchangePurpose(label)));
    2686         148 :             obj.pushKV("amount", ValueFromAmount(nAmount));
    2687          74 :             if (nConf == std::numeric_limits<int>::max()) nConf = 0;
    2688          74 :             obj.pushKV("confirmations", nConf);
    2689          74 :             obj.pushKV("bcconfirmations", nConf);       // DEPRECATED in 4.3.99
    2690          74 :             obj.pushKV("label", label);
    2691         148 :             UniValue transactions(UniValue::VARR);
    2692          74 :             if (it != mapTally.end()) {
    2693         275 :                 for (const uint256 &item : (*it).second.txids) {
    2694         432 :                     transactions.push_back(item.GetHex());
    2695             :                 }
    2696             :             }
    2697          74 :             obj.pushKV("txids", transactions);
    2698          74 :             ret.push_back(obj);
    2699             :         }
    2700             :     }
    2701             : 
    2702          78 :     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         156 :     return ret;
    2717             : }
    2718             : 
    2719          75 : UniValue listreceivedbyaddress(const JSONRPCRequest& request)
    2720             : {
    2721          75 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    2722             : 
    2723          75 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    2724           0 :         return NullUniValue;
    2725             : 
    2726          75 :     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          75 :     pwallet->BlockUntilSyncedToCurrentChain();
    2759             : 
    2760         224 :     LOCK2(cs_main, pwallet->cs_wallet);
    2761          75 :     int nBlockHeight = chainActive.Height();
    2762          75 :     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         424 : static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
    2994             : {
    2995         424 :     if (IsValidDestination(dest))
    2996        1209 :         entry.pushKV("address", EncodeDestination(dest));
    2997         424 : }
    2998             : 
    2999         342 : 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         342 :     AssertLockHeld(cs_main);
    3002             : 
    3003         342 :     CAmount nFee;
    3004         342 :     std::list<COutputEntry> listReceived;
    3005         342 :     std::list<COutputEntry> listSent;
    3006             : 
    3007         342 :     wtx.GetAmounts(listReceived, listSent, nFee, filter);
    3008             : 
    3009         342 :     bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
    3010             : 
    3011             :     // Sent
    3012         342 :     if ((!listSent.empty() || nFee != 0)) {
    3013         241 :         for (const COutputEntry& s : listSent) {
    3014         266 :             UniValue entry(UniValue::VOBJ);
    3015         133 :             if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY))
    3016           0 :                 entry.pushKV("involvesWatchonly", true);
    3017         133 :             MaybePushAddress(entry, s.destination);
    3018         133 :             entry.pushKV("category", "send");
    3019         266 :             entry.pushKV("amount", ValueFromAmount(-s.amount));
    3020         133 :             if (pwallet->HasAddressBook(s.destination)) {
    3021         110 :                 entry.pushKV("label", pwallet->GetNameForAddressBookEntry(s.destination));
    3022             :             }
    3023         133 :             entry.pushKV("vout", s.vout);
    3024         266 :             entry.pushKV("fee", ValueFromAmount(-nFee));
    3025         133 :             if (fLong)
    3026          55 :                 WalletTxToJSON(wtx, entry);
    3027         133 :             ret.push_back(entry);
    3028             :         }
    3029             :     }
    3030             : 
    3031             :     // Received
    3032         342 :     int depth = wtx.GetDepthInMainChain();
    3033         342 :     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         342 : }
    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          79 : UniValue gettransaction(const JSONRPCRequest& request)
    3278             : {
    3279          79 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3280             : 
    3281          79 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3282           0 :         return NullUniValue;
    3283             : 
    3284          79 :     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          79 :     pwallet->BlockUntilSyncedToCurrentChain();
    3325             : 
    3326         235 :     LOCK2(cs_main, pwallet->cs_wallet);
    3327             : 
    3328          79 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    3329             : 
    3330          79 :     isminefilter filter = ISMINE_SPENDABLE_ALL | ISMINE_COLD;
    3331          79 :     if (request.params.size() > 1)
    3332           2 :         if (request.params[1].get_bool())
    3333           2 :             filter = filter | ISMINE_WATCH_ONLY;
    3334             : 
    3335         156 :     UniValue entry(UniValue::VOBJ);
    3336          79 :     auto it = pwallet->mapWallet.find(hash);
    3337          79 :     if (it == pwallet->mapWallet.end()) {
    3338           4 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
    3339             :     }
    3340          77 :     const CWalletTx& wtx = it->second;
    3341             : 
    3342          77 :     CAmount nCredit = wtx.GetCredit(filter);
    3343          77 :     CAmount nDebit = wtx.GetDebit(filter);
    3344          77 :     CAmount nNet = nCredit - nDebit;
    3345          77 :     CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
    3346             : 
    3347         154 :     entry.pushKV("amount", ValueFromAmount(nNet - nFee));
    3348          77 :     if (wtx.IsFromMe(filter))
    3349         156 :         entry.pushKV("fee", ValueFromAmount(nFee));
    3350             : 
    3351          77 :     WalletTxToJSON(wtx, entry);
    3352             : 
    3353          77 :     UniValue details(UniValue::VARR);
    3354          77 :     ListTransactions(pwallet, wtx, 0, false, details, filter);
    3355          77 :     entry.pushKV("details", details);
    3356             : 
    3357         154 :     std::string strHex = EncodeHexTx(*wtx.tx);
    3358          77 :     entry.pushKV("hex", strHex);
    3359             : 
    3360          77 :     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         150 : UniValue listunspent(const JSONRPCRequest& request)
    3713             : {
    3714         150 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    3715             : 
    3716         150 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    3717           0 :         return NullUniValue;
    3718             : 
    3719         150 :     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         150 :     pwallet->BlockUntilSyncedToCurrentChain();
    3779             : 
    3780         150 :     int nMinDepth = 1;
    3781         150 :     if (request.params.size() > 0) {
    3782          39 :         RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
    3783          39 :         nMinDepth = request.params[0].get_int();
    3784             :     }
    3785             : 
    3786         150 :     int nMaxDepth = 9999999;
    3787         150 :     if (request.params.size() > 1) {
    3788          34 :         RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
    3789          34 :         nMaxDepth = request.params[1].get_int();
    3790             :     }
    3791             : 
    3792         150 :     CWallet::AvailableCoinsFilter coinFilter;
    3793             : 
    3794         300 :     std::set<CTxDestination> destinations;
    3795         150 :     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         150 :     int nWatchonlyConfig = 1;
    3812         150 :     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         150 :     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         300 :     CCoinControl coinControl;
    3848         150 :     coinControl.fAllowWatchOnly = nWatchonlyConfig == 2;
    3849             : 
    3850         150 :     bool include_unsafe = request.params.size() < 6 || request.params[5].get_bool();
    3851         150 :     coinFilter.fOnlySafe = !include_unsafe;
    3852             : 
    3853         300 :     UniValue results(UniValue::VARR);
    3854         300 :     std::vector<COutput> vecOutputs;
    3855             : 
    3856         450 :     LOCK2(cs_main, pwallet->cs_wallet);
    3857         150 :     pwallet->AvailableCoins(&vecOutputs, &coinControl, coinFilter);
    3858     1968590 :     for (const COutput& out : vecOutputs) {
    3859     1968440 :         if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
    3860          70 :             continue;
    3861             : 
    3862     1968370 :         UniValue entry(UniValue::VOBJ);
    3863     3936750 :         entry.pushKV("txid", out.tx->GetHash().GetHex());
    3864     1968370 :         entry.pushKV("vout", out.i);
    3865     1972530 :         entry.pushKV("generated", out.tx->IsCoinStake() || out.tx->IsCoinBase());
    3866     3936750 :         CTxDestination address;
    3867     1968370 :         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
    3868     1968370 :         if (ExtractDestination(scriptPubKey, address)) {
    3869     3936750 :             entry.pushKV("address", EncodeDestination(address));
    3870     1968370 :             if (pwallet->HasAddressBook(address)) {
    3871     3849220 :                 entry.pushKV("label", pwallet->GetNameForAddressBookEntry(address));
    3872             :             }
    3873     1968370 :             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     5905120 :         entry.pushKV("scriptPubKey", HexStr(scriptPubKey));
    3881     3936750 :         entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
    3882     1968370 :         entry.pushKV("confirmations", out.nDepth);
    3883     1968370 :         entry.pushKV("spendable", out.fSpendable);
    3884     1968370 :         entry.pushKV("solvable", out.fSolvable);
    3885     1968370 :         entry.pushKV("safe", out.fSafe);
    3886     1968370 :         results.push_back(entry);
    3887             :     }
    3888             : 
    3889         150 :     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          22 : UniValue lockunspent(const JSONRPCRequest& request)
    4041             : {
    4042          22 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4043             : 
    4044          22 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4045           0 :         return NullUniValue;
    4046             : 
    4047          22 :     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          22 :     pwallet->BlockUntilSyncedToCurrentChain();
    4087             : 
    4088          66 :     LOCK2(cs_main, pwallet->cs_wallet);
    4089             : 
    4090          22 :     if (request.params.size() == 2)
    4091           0 :         RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VBOOL});
    4092             :     else
    4093          44 :         RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VBOOL, UniValue::VARR});
    4094             : 
    4095          22 :     bool fUnlock = request.params[0].get_bool();
    4096          22 :     bool transparent = request.params[1].get_bool();
    4097             : 
    4098          22 :     if (request.params.size() == 2) {
    4099           0 :         if (fUnlock) transparent ? pwallet->UnlockAllCoins() : pwallet->UnlockAllNotes();
    4100           0 :         return true;
    4101             :     }
    4102             : 
    4103          22 :     UniValue output_request = request.params[2].get_array();
    4104             : 
    4105             :     // Create and validate the COutPoints first.
    4106          44 :     std::vector<COutPoint> outputs;
    4107          22 :     std::vector<SaplingOutPoint> saplingOutputs;
    4108          22 :     transparent ? outputs.reserve(output_request.size()) : saplingOutputs.reserve(output_request.size());
    4109             : 
    4110          44 :     for (unsigned int idx = 0; idx < output_request.size(); idx++) {
    4111          22 :         const UniValue& output = output_request[idx];
    4112          22 :         if (!output.isObject())
    4113           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
    4114          22 :         const UniValue& o = output.get_obj();
    4115             : 
    4116          88 :         RPCTypeCheckObj(o,
    4117             :             {
    4118          22 :                 {"txid", UniValueType(UniValue::VSTR)},
    4119          22 :                 {"vout", UniValueType(UniValue::VNUM)},
    4120          66 :             });
    4121             : 
    4122          22 :         const uint256 txid(ParseHashO(o, "txid"));
    4123             : 
    4124          22 :         const int nOutput = find_value(o, "vout").get_int();
    4125          22 :         if (nOutput < 0) {
    4126           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
    4127             :         }
    4128             : 
    4129          22 :         bool is_locked = false;
    4130             : 
    4131          22 :         const auto it = pwallet->mapWallet.find(txid);
    4132          22 :         if (it == pwallet->mapWallet.end()) {
    4133           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
    4134             :         }
    4135             : 
    4136          22 :         const CWalletTx& wtx = it->second;
    4137          22 :         if (transparent) {
    4138          20 :             const COutPoint outpt(txid, nOutput);
    4139          20 :             if (outpt.n >= wtx.tx->vout.size()) {
    4140           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
    4141             :             }
    4142             : 
    4143          20 :             if (pwallet->IsSpent(outpt.hash, outpt.n)) {
    4144           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
    4145             :             }
    4146          20 :             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          22 :         if (fUnlock && !is_locked) {
    4159           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
    4160             :         }
    4161             : 
    4162          22 :         if (!fUnlock && is_locked) {
    4163           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
    4164             :         }
    4165             : 
    4166          22 :         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          42 :     for (const COutPoint& outpt : outputs) {
    4171          20 :         if (fUnlock) pwallet->UnlockCoin(outpt);
    4172          19 :         else pwallet->LockCoin(outpt);
    4173             :     }
    4174             : 
    4175          24 :     for (const SaplingOutPoint& op : saplingOutputs) {
    4176           2 :         if (fUnlock) pwallet->UnlockNote(op);
    4177             :         else
    4178           1 :             pwallet->LockNote(op);
    4179             :     }
    4180             : 
    4181          22 :     return true;
    4182             : }
    4183             : 
    4184          52 : UniValue listlockunspent(const JSONRPCRequest& request)
    4185             : {
    4186          52 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4187             : 
    4188          52 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4189           0 :         return NullUniValue;
    4190             : 
    4191          52 :     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         156 :     LOCK2(cs_main, pwallet->cs_wallet);
    4228             : 
    4229             : 
    4230         104 :     UniValue ret(UniValue::VOBJ);
    4231         104 :     UniValue transparent(UniValue::VARR);
    4232          52 :     UniValue shielded(UniValue::VARR);
    4233             : 
    4234         104 :     std::set<COutPoint> vOutpts = pwallet->ListLockedCoins();
    4235         220 :     for (const COutPoint& outpt : vOutpts) {
    4236         336 :         UniValue o(UniValue::VOBJ);
    4237             : 
    4238         336 :         o.pushKV("txid", outpt.hash.GetHex());
    4239         168 :         o.pushKV("vout", (int)outpt.n);
    4240         168 :         transparent.push_back(o);
    4241             :     }
    4242             : 
    4243         104 :     std::set<SaplingOutPoint> sOps = pwallet->ListLockedNotes();
    4244          54 :     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          52 :     ret.pushKV("transparent", transparent);
    4252          52 :     ret.pushKV("shielded", shielded);
    4253          52 :     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         561 : UniValue getstakingstatus(const JSONRPCRequest& request)
    4405             : {
    4406         561 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
    4407             : 
    4408         561 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
    4409           0 :         return NullUniValue;
    4410             : 
    4411         561 :     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         561 :     if (!pwallet)
    4439           0 :         throw JSONRPCError(RPC_IN_WARMUP, "Try again after active chain is loaded");
    4440         561 :     {
    4441        1683 :         LOCK2(cs_main, &pwallet->cs_wallet);
    4442        1122 :         UniValue obj(UniValue::VOBJ);
    4443         561 :         obj.pushKV("staking_status", pwallet->pStakerStatus->IsActive());
    4444        1122 :         obj.pushKV("staking_enabled", gArgs.GetBoolArg("-staking", DEFAULT_STAKING));
    4445         561 :         bool fColdStaking = gArgs.GetBoolArg("-coldstaking", true);
    4446         561 :         obj.pushKV("coldstaking_enabled", fColdStaking);
    4447         561 :         obj.pushKV("haveconnections", (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) > 0));
    4448         561 :         obj.pushKV("mnsync", !masternodeSync.NotCompleted());
    4449         561 :         obj.pushKV("walletunlocked", !pwallet->IsLocked());
    4450        1122 :         std::vector<CStakeableOutput> vCoins;
    4451         561 :         pwallet->StakeableCoins(&vCoins);
    4452         561 :         obj.pushKV("stakeablecoins", (int)vCoins.size());
    4453        1122 :         obj.pushKV("stakingbalance", ValueFromAmount(pwallet->GetStakingBalance(fColdStaking)));
    4454        1122 :         obj.pushKV("stakesplitthreshold", ValueFromAmount(pwallet->nStakeSplitThreshold));
    4455         561 :         CStakerStatus* ss = pwallet->pStakerStatus;
    4456         561 :         if (ss) {
    4457         561 :             obj.pushKV("lastattempt_age", (int)(GetTime() - ss->GetLastTime()));
    4458        1107 :             obj.pushKV("lastattempt_depth", (chainActive.Height() - ss->GetLastHeight()));
    4459        1683 :             obj.pushKV("lastattempt_hash", ss->GetLastHash().GetHex());
    4460         561 :             obj.pushKV("lastattempt_coins", ss->GetLastCoins());
    4461        1122 :             obj.pushKV("lastattempt_tries", ss->GetLastTries());
    4462             :         }
    4463         561 :         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         411 : void RegisterWalletRPCCommands(CRPCTable &tableRPC)
    4854             : {
    4855         411 :     if (gArgs.GetBoolArg("-disablewallet", false)) {
    4856             :         return;
    4857             :     }
    4858       30800 :     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) {
    4859       30400 :         tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
    4860             :     }
    4861             : }

Generated by: LCOV version 1.14