LCOV - code coverage report
Current view: top level - src/wallet - rpcwallet.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 2755 2846 96.8 %
Date: 2020-09-26 01:30:44 Functions: 93 95 97.9 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2020 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <amount.h>
       7             : #include <core_io.h>
       8             : #include <interfaces/chain.h>
       9             : #include <key_io.h>
      10             : #include <node/context.h>
      11             : #include <outputtype.h>
      12             : #include <policy/feerate.h>
      13             : #include <policy/fees.h>
      14             : #include <policy/policy.h>
      15             : #include <policy/rbf.h>
      16             : #include <rpc/rawtransaction_util.h>
      17             : #include <rpc/server.h>
      18             : #include <rpc/util.h>
      19             : #include <script/descriptor.h>
      20             : #include <script/sign.h>
      21             : #include <util/bip32.h>
      22             : #include <util/fees.h>
      23             : #include <util/message.h> // For MessageSign()
      24             : #include <util/moneystr.h>
      25             : #include <util/ref.h>
      26             : #include <util/string.h>
      27             : #include <util/system.h>
      28             : #include <util/translation.h>
      29             : #include <util/url.h>
      30             : #include <util/vector.h>
      31             : #include <wallet/coincontrol.h>
      32             : #include <wallet/context.h>
      33             : #include <wallet/feebumper.h>
      34             : #include <wallet/load.h>
      35             : #include <wallet/rpcwallet.h>
      36             : #include <wallet/wallet.h>
      37             : #include <wallet/walletdb.h>
      38             : #include <wallet/walletutil.h>
      39             : 
      40             : #include <stdint.h>
      41             : 
      42             : #include <univalue.h>
      43             : 
      44             : 
      45             : using interfaces::FoundBlock;
      46             : 
      47         650 : static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
      48         650 : static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
      49             : 
      50             : static const uint32_t WALLET_BTC_KB_TO_SAT_B = COIN / 1000; // 1 sat / B = 0.00001 BTC / kB
      51             : 
      52        1364 : static inline bool GetAvoidReuseFlag(const CWallet* const pwallet, const UniValue& param) {
      53        1364 :     bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
      54        1364 :     bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
      55             : 
      56        1364 :     if (avoid_reuse && !can_avoid_reuse) {
      57           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
      58             :     }
      59             : 
      60        1364 :     return avoid_reuse;
      61           0 : }
      62             : 
      63             : 
      64             : /** Used by RPC commands that have an include_watchonly parameter.
      65             :  *  We default to true for watchonly wallets if include_watchonly isn't
      66             :  *  explicitly set.
      67             :  */
      68        1522 : static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& pwallet)
      69             : {
      70        1522 :     if (include_watchonly.isNull()) {
      71             :         // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
      72         824 :         return pwallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
      73             :     }
      74             : 
      75             :     // otherwise return whatever include_watchonly was set to
      76         698 :     return include_watchonly.get_bool();
      77        1522 : }
      78             : 
      79             : 
      80             : /** Checks if a CKey is in the given CWallet compressed or otherwise*/
      81           7 : bool HaveKey(const SigningProvider& wallet, const CKey& key)
      82             : {
      83           7 :     CKey key2;
      84           7 :     key2.Set(key.begin(), key.end(), !key.IsCompressed());
      85           7 :     return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
      86           7 : }
      87             : 
      88       17723 : bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
      89             : {
      90       17723 :     if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
      91             :         // wallet endpoint was used
      92        1730 :         wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
      93        1730 :         return true;
      94             :     }
      95       15993 :     return false;
      96       17723 : }
      97             : 
      98       17596 : std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
      99             : {
     100       17622 :     CHECK_NONFATAL(!request.fHelp);
     101       17596 :     std::string wallet_name;
     102       17596 :     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
     103        1695 :         std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
     104        1695 :         if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
     105             :         return pwallet;
     106        1695 :     }
     107             : 
     108       15901 :     std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
     109       15901 :     if (wallets.size() == 1) {
     110       15885 :         return wallets[0];
     111             :     }
     112             : 
     113          16 :     if (wallets.empty()) {
     114           4 :         throw JSONRPCError(
     115           4 :             RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)");
     116             :     }
     117          12 :     throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
     118          12 :         "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
     119       17606 : }
     120             : 
     121        4741 : void EnsureWalletIsUnlocked(const CWallet* pwallet)
     122             : {
     123        4741 :     if (pwallet->IsLocked()) {
     124          13 :         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
     125             :     }
     126        4741 : }
     127             : 
     128         499 : WalletContext& EnsureWalletContext(const util::Ref& context)
     129             : {
     130         499 :     if (!context.Has<WalletContext>()) {
     131           0 :         throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
     132             :     }
     133         499 :     return context.Get<WalletContext>();
     134           0 : }
     135             : 
     136             : // also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
     137         999 : LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
     138             : {
     139         999 :     LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
     140         999 :     if (!spk_man && also_create) {
     141           7 :         spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
     142           7 :     }
     143         999 :     if (!spk_man) {
     144           9 :         throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
     145             :     }
     146         990 :     return *spk_man;
     147           9 : }
     148             : 
     149        2028 : static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry)
     150             : {
     151        2028 :     int confirms = wtx.GetDepthInMainChain();
     152        2028 :     entry.pushKV("confirmations", confirms);
     153        2028 :     if (wtx.IsCoinBase())
     154        1132 :         entry.pushKV("generated", true);
     155        2028 :     if (confirms > 0)
     156             :     {
     157        1475 :         entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
     158        1475 :         entry.pushKV("blockheight", wtx.m_confirm.block_height);
     159        1475 :         entry.pushKV("blockindex", wtx.m_confirm.nIndex);
     160        1475 :         int64_t block_time;
     161        1475 :         CHECK_NONFATAL(chain.findBlock(wtx.m_confirm.hashBlock, FoundBlock().time(block_time)));
     162        1475 :         entry.pushKV("blocktime", block_time);
     163        1475 :     } else {
     164         553 :         entry.pushKV("trusted", wtx.IsTrusted());
     165             :     }
     166        2028 :     uint256 hash = wtx.GetHash();
     167        2028 :     entry.pushKV("txid", hash.GetHex());
     168        2028 :     UniValue conflicts(UniValue::VARR);
     169        2132 :     for (const uint256& conflict : wtx.GetConflicts())
     170         104 :         conflicts.push_back(conflict.GetHex());
     171        2028 :     entry.pushKV("walletconflicts", conflicts);
     172        2028 :     entry.pushKV("time", wtx.GetTxTime());
     173        2028 :     entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
     174             : 
     175             :     // Add opt-in RBF status
     176        2028 :     std::string rbfStatus = "no";
     177        2028 :     if (confirms <= 0) {
     178         553 :         RBFTransactionState rbfState = chain.isRBFOptIn(*wtx.tx);
     179         553 :         if (rbfState == RBFTransactionState::UNKNOWN)
     180         228 :             rbfStatus = "unknown";
     181         325 :         else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125)
     182          37 :             rbfStatus = "yes";
     183         553 :     }
     184        2028 :     entry.pushKV("bip125-replaceable", rbfStatus);
     185             : 
     186        2041 :     for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
     187          13 :         entry.pushKV(item.first, item.second);
     188        2028 : }
     189             : 
     190         430 : static std::string LabelFromValue(const UniValue& value)
     191             : {
     192         430 :     std::string label = value.get_str();
     193         430 :     if (label == "*")
     194           0 :         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
     195             :     return label;
     196         430 : }
     197             : 
     198             : /**
     199             :  * Update coin control with fee estimation based on the given parameters
     200             :  *
     201             :  * @param[in]     pwallet        Wallet pointer
     202             :  * @param[in,out] cc             Coin control which is to be updated
     203             :  * @param[in]     estimate_mode  String value (e.g. "ECONOMICAL")
     204             :  * @param[in]     estimate_param Parameter (blocks to confirm, explicit fee rate, etc)
     205             :  * @throws a JSONRPCError if estimate_mode is unknown, or if estimate_param is missing when required
     206             :  */
     207        1236 : static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const UniValue& estimate_mode, const UniValue& estimate_param)
     208             : {
     209        1236 :     if (!estimate_mode.isNull()) {
     210          26 :         if (!FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) {
     211           8 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
     212             :         }
     213             :     }
     214             : 
     215        1234 :     if (cc.m_fee_mode == FeeEstimateMode::BTC_KB || cc.m_fee_mode == FeeEstimateMode::SAT_B) {
     216          22 :         if (estimate_param.isNull()) {
     217           6 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Selected estimate_mode requires a fee rate");
     218             :         }
     219             : 
     220          16 :         CAmount fee_rate = AmountFromValue(estimate_param);
     221          16 :         if (cc.m_fee_mode == FeeEstimateMode::SAT_B) {
     222           5 :             fee_rate /= WALLET_BTC_KB_TO_SAT_B;
     223           5 :         }
     224             : 
     225           9 :         cc.m_feerate = CFeeRate(fee_rate);
     226             : 
     227             :         // default RBF to true for explicit fee rate modes
     228           9 :         if (cc.m_signal_bip125_rbf == nullopt) cc.m_signal_bip125_rbf = true;
     229        1221 :     } else if (!estimate_param.isNull()) {
     230           2 :         cc.m_confirm_target = ParseConfirmTarget(estimate_param, pwallet->chain().estimateMaxBlocks());
     231           2 :     }
     232        1229 : }
     233             : 
     234        8670 : static UniValue getnewaddress(const JSONRPCRequest& request)
     235             : {
     236       34708 :             RPCHelpMan{"getnewaddress",
     237        8670 :                 "\nReturns a new Bitcoin address for receiving payments.\n"
     238             :                 "If 'label' is specified, it is added to the address book \n"
     239             :                 "so payments received with the address will be associated with 'label'.\n",
     240       26016 :                 {
     241        8670 :                     {"label", RPCArg::Type::STR, /* default */ "\"\"", "The label name for the address to be linked to. 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."},
     242        8670 :                     {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
     243             :                 },
     244        8670 :                 RPCResult{
     245        8670 :                     RPCResult::Type::STR, "address", "The new bitcoin address"
     246             :                 },
     247        8670 :                 RPCExamples{
     248        8670 :                     HelpExampleCli("getnewaddress", "")
     249        8670 :             + HelpExampleRpc("getnewaddress", "")
     250             :                 },
     251        8670 :             }.Check(request);
     252             : 
     253        8664 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     254        8664 :     if (!wallet) return NullUniValue;
     255        8656 :     CWallet* const pwallet = wallet.get();
     256             : 
     257        8656 :     LOCK(pwallet->cs_wallet);
     258             : 
     259        8656 :     if (!pwallet->CanGetAddresses()) {
     260          20 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
     261             :     }
     262             : 
     263             :     // Parse the label first so we don't generate a key if there's an error
     264        8636 :     std::string label;
     265        8636 :     if (!request.params[0].isNull())
     266         260 :         label = LabelFromValue(request.params[0]);
     267             : 
     268        8636 :     OutputType output_type = pwallet->m_default_address_type;
     269        8636 :     if (!request.params[1].isNull()) {
     270        1478 :         if (!ParseOutputType(request.params[1].get_str(), output_type)) {
     271           1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
     272             :         }
     273             :     }
     274             : 
     275        8635 :     CTxDestination dest;
     276        8635 :     std::string error;
     277        8635 :     if (!pwallet->GetNewDestination(output_type, label, dest, error)) {
     278           7 :         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
     279             :     }
     280             : 
     281        8628 :     return EncodeDestination(dest);
     282        8692 : }
     283             : 
     284          95 : static UniValue getrawchangeaddress(const JSONRPCRequest& request)
     285             : {
     286         311 :             RPCHelpMan{"getrawchangeaddress",
     287          95 :                 "\nReturns a new Bitcoin address, for receiving change.\n"
     288             :                 "This is for use with raw transactions, NOT normal use.\n",
     289         190 :                 {
     290          95 :                     {"address_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
     291             :                 },
     292          95 :                 RPCResult{
     293          95 :                     RPCResult::Type::STR, "address", "The address"
     294             :                 },
     295          95 :                 RPCExamples{
     296          95 :                     HelpExampleCli("getrawchangeaddress", "")
     297          95 :             + HelpExampleRpc("getrawchangeaddress", "")
     298             :                 },
     299          95 :             }.Check(request);
     300             : 
     301          91 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     302          91 :     if (!wallet) return NullUniValue;
     303          91 :     CWallet* const pwallet = wallet.get();
     304             : 
     305          91 :     LOCK(pwallet->cs_wallet);
     306             : 
     307          91 :     if (!pwallet->CanGetAddresses(true)) {
     308          22 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
     309             :     }
     310             : 
     311          69 :     OutputType output_type = pwallet->m_default_change_type.get_value_or(pwallet->m_default_address_type);
     312          69 :     if (!request.params[0].isNull()) {
     313          14 :         if (!ParseOutputType(request.params[0].get_str(), output_type)) {
     314           2 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
     315             :         }
     316             :     }
     317             : 
     318          67 :     CTxDestination dest;
     319          67 :     std::string error;
     320          67 :     if (!pwallet->GetNewChangeDestination(output_type, dest, error)) {
     321           2 :         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
     322             :     }
     323          65 :     return EncodeDestination(dest);
     324         107 : }
     325             : 
     326             : 
     327          32 : static UniValue setlabel(const JSONRPCRequest& request)
     328             : {
     329         129 :             RPCHelpMan{"setlabel",
     330          32 :                 "\nSets the label associated with the given address.\n",
     331         100 :                 {
     332          32 :                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to be associated with a label."},
     333          32 :                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label to assign to the address."},
     334             :                 },
     335          32 :                 RPCResult{RPCResult::Type::NONE, "", ""},
     336          32 :                 RPCExamples{
     337          32 :                     HelpExampleCli("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\" \"tabby\"")
     338          32 :             + HelpExampleRpc("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\", \"tabby\"")
     339             :                 },
     340          32 :             }.Check(request);
     341             : 
     342          28 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     343          28 :     if (!wallet) return NullUniValue;
     344          28 :     CWallet* const pwallet = wallet.get();
     345             : 
     346          28 :     LOCK(pwallet->cs_wallet);
     347             : 
     348          28 :     CTxDestination dest = DecodeDestination(request.params[0].get_str());
     349          28 :     if (!IsValidDestination(dest)) {
     350           1 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
     351             :     }
     352             : 
     353          27 :     std::string label = LabelFromValue(request.params[1]);
     354             : 
     355          27 :     if (pwallet->IsMine(dest)) {
     356          27 :         pwallet->SetAddressBook(dest, label, "receive");
     357          27 :     } else {
     358           0 :         pwallet->SetAddressBook(dest, label, "send");
     359             :     }
     360             : 
     361          27 :     return NullUniValue;
     362          52 : }
     363             : 
     364        1109 : void ParseRecipients(const UniValue& address_amounts, const UniValue& subtract_fee_outputs, std::vector<CRecipient> &recipients) {
     365        1109 :     std::set<CTxDestination> destinations;
     366             :     int i = 0;
     367        5255 :     for (const std::string& address: address_amounts.getKeys()) {
     368        4146 :         CTxDestination dest = DecodeDestination(address);
     369        4146 :         if (!IsValidDestination(dest)) {
     370           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + address);
     371             :         }
     372             : 
     373        4146 :         if (destinations.count(dest)) {
     374           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + address);
     375             :         }
     376        4146 :         destinations.insert(dest);
     377             : 
     378        4146 :         CScript script_pub_key = GetScriptForDestination(dest);
     379        4146 :         CAmount amount = AmountFromValue(address_amounts[i++]);
     380             : 
     381             :         bool subtract_fee = false;
     382        4172 :         for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); idx++) {
     383          30 :             const UniValue& addr = subtract_fee_outputs[idx];
     384          30 :             if (addr.get_str() == address) {
     385             :                 subtract_fee = true;
     386          30 :             }
     387             :         }
     388             : 
     389        4142 :         CRecipient recipient = {script_pub_key, amount, subtract_fee};
     390        4142 :         recipients.push_back(recipient);
     391        4146 :     }
     392        1113 : }
     393             : 
     394        1105 : UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value)
     395             : {
     396        1105 :     EnsureWalletIsUnlocked(pwallet);
     397             : 
     398             :     // Shuffle recipient list
     399        1105 :     std::shuffle(recipients.begin(), recipients.end(), FastRandomContext());
     400             : 
     401             :     // Send
     402        1105 :     CAmount nFeeRequired = 0;
     403        1105 :     int nChangePosRet = -1;
     404        1105 :     bilingual_str error;
     405        1105 :     CTransactionRef tx;
     406        1105 :     bool fCreated = pwallet->CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
     407        1105 :     if (!fCreated) {
     408          13 :         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
     409             :     }
     410        1092 :     pwallet->CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
     411        1092 :     return tx->GetHash().GetHex();
     412        1105 : }
     413             : 
     414        1009 : static UniValue sendtoaddress(const JSONRPCRequest& request)
     415             : {
     416       11116 :             RPCHelpMan{"sendtoaddress",
     417        1009 :                 "\nSend an amount to a given address." +
     418             :         HELP_REQUIRING_PASSPHRASE,
     419       10094 :                 {
     420        1009 :                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to send to."},
     421        1009 :                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
     422        1009 :                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n"
     423             :             "                             This is not part of the transaction, just kept in your wallet."},
     424        1009 :                     {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n"
     425             :             "                             to which you're sending the transaction. This is not part of the \n"
     426             :             "                             transaction, just kept in your wallet."},
     427        1009 :                     {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n"
     428             :             "                             The recipient will receive less bitcoins than you enter in the amount field."},
     429        1009 :                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
     430        1009 :                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
     431        2018 :                     {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
     432        1009 :             "       \"" + FeeModes("\"\n\"") + "\""},
     433        1009 :                     {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
     434             :             "                             dirty if they have previously been used in a transaction."},
     435             :                 },
     436        1009 :                 RPCResult{
     437        1009 :                     RPCResult::Type::STR_HEX, "txid", "The transaction id."
     438             :                 },
     439        1009 :                 RPCExamples{
     440        1009 :                     HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1")
     441        1009 :             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"seans outpost\"")
     442        1009 :             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" true")
     443        1009 :             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" false true 0.00002 " + (CURRENCY_UNIT + "/kB"))
     444        1009 :             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" false true 2 " + (CURRENCY_ATOM + "/B"))
     445        1009 :             + HelpExampleRpc("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 0.1, \"donation\", \"seans outpost\"")
     446             :                 },
     447        1009 :             }.Check(request);
     448             : 
     449        1005 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     450        1005 :     if (!wallet) return NullUniValue;
     451        1005 :     CWallet* const pwallet = wallet.get();
     452             : 
     453             :     // Make sure the results are valid at least up to the most recent block
     454             :     // the user could have gotten from another RPC command prior to now
     455        1005 :     pwallet->BlockUntilSyncedToCurrentChain();
     456             : 
     457        1005 :     LOCK(pwallet->cs_wallet);
     458             : 
     459             :     // Wallet comments
     460        1005 :     mapValue_t mapValue;
     461        1005 :     if (!request.params[2].isNull() && !request.params[2].get_str().empty())
     462           1 :         mapValue["comment"] = request.params[2].get_str();
     463        1005 :     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
     464           1 :         mapValue["to"] = request.params[3].get_str();
     465             : 
     466             :     bool fSubtractFeeFromAmount = false;
     467        1005 :     if (!request.params[4].isNull()) {
     468          28 :         fSubtractFeeFromAmount = request.params[4].get_bool();
     469          28 :     }
     470             : 
     471        1005 :     CCoinControl coin_control;
     472        1005 :     if (!request.params[5].isNull()) {
     473           2 :         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
     474           2 :     }
     475             : 
     476        1005 :     coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(pwallet, request.params[8]);
     477             :     // We also enable partial spend avoidance if reuse avoidance is set.
     478        1005 :     coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
     479             : 
     480        1005 :     SetFeeEstimateMode(pwallet, coin_control, request.params[7], request.params[6]);
     481             : 
     482        1001 :     EnsureWalletIsUnlocked(pwallet);
     483             : 
     484        1000 :     UniValue address_amounts(UniValue::VOBJ);
     485        1000 :     const std::string address = request.params[0].get_str();
     486        1000 :     address_amounts.pushKV(address, request.params[1]);
     487        1000 :     UniValue subtractFeeFromAmount(UniValue::VARR);
     488        1000 :     if (fSubtractFeeFromAmount) {
     489          26 :         subtractFeeFromAmount.push_back(address);
     490             :     }
     491             : 
     492        1000 :     std::vector<CRecipient> recipients;
     493        1000 :     ParseRecipients(address_amounts, subtractFeeFromAmount, recipients);
     494             : 
     495         996 :     return SendMoney(pwallet, coin_control, recipients, mapValue);
     496        1085 : }
     497             : 
     498           8 : static UniValue listaddressgroupings(const JSONRPCRequest& request)
     499             : {
     500          40 :             RPCHelpMan{"listaddressgroupings",
     501           8 :                 "\nLists groups of addresses which have had their common ownership\n"
     502             :                 "made public by common use as inputs or as the resulting change\n"
     503             :                 "in past transactions\n",
     504           8 :                 {},
     505           8 :                 RPCResult{
     506           8 :                     RPCResult::Type::ARR, "", "",
     507          16 :                     {
     508          16 :                         {RPCResult::Type::ARR, "", "",
     509          16 :                         {
     510          16 :                             {RPCResult::Type::ARR, "", "",
     511          36 :                             {
     512           8 :                                 {RPCResult::Type::STR, "address", "The bitcoin address"},
     513           8 :                                 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
     514           8 :                                 {RPCResult::Type::STR, "label", /* optional */ true, "The label"},
     515             :                             }},
     516             :                         }},
     517             :                     }
     518             :                 },
     519           8 :                 RPCExamples{
     520           8 :                     HelpExampleCli("listaddressgroupings", "")
     521           8 :             + HelpExampleRpc("listaddressgroupings", "")
     522             :                 },
     523           8 :             }.Check(request);
     524             : 
     525           4 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     526           4 :     if (!wallet) return NullUniValue;
     527           4 :     const CWallet* const pwallet = wallet.get();
     528             : 
     529             :     // Make sure the results are valid at least up to the most recent block
     530             :     // the user could have gotten from another RPC command prior to now
     531           4 :     pwallet->BlockUntilSyncedToCurrentChain();
     532             : 
     533           4 :     LOCK(pwallet->cs_wallet);
     534             : 
     535           4 :     UniValue jsonGroupings(UniValue::VARR);
     536           4 :     std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
     537          10 :     for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
     538           6 :         UniValue jsonGrouping(UniValue::VARR);
     539          14 :         for (const CTxDestination& address : grouping)
     540             :         {
     541           8 :             UniValue addressInfo(UniValue::VARR);
     542           8 :             addressInfo.push_back(EncodeDestination(address));
     543           8 :             addressInfo.push_back(ValueFromAmount(balances[address]));
     544             :             {
     545           8 :                 const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
     546           8 :                 if (address_book_entry) {
     547           8 :                     addressInfo.push_back(address_book_entry->GetLabel());
     548             :                 }
     549           0 :             }
     550           8 :             jsonGrouping.push_back(addressInfo);
     551           8 :         }
     552           6 :         jsonGroupings.push_back(jsonGrouping);
     553           6 :     }
     554           4 :     return jsonGroupings;
     555          32 : }
     556             : 
     557          26 : static UniValue signmessage(const JSONRPCRequest& request)
     558             : {
     559         114 :             RPCHelpMan{"signmessage",
     560          26 :                 "\nSign a message with the private key of an address" +
     561             :         HELP_REQUIRING_PASSPHRASE,
     562          82 :                 {
     563          26 :                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the private key."},
     564          26 :                     {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
     565             :                 },
     566          26 :                 RPCResult{
     567          26 :                     RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
     568             :                 },
     569          26 :                 RPCExamples{
     570          26 :             "\nUnlock the wallet for 30 seconds\n"
     571          26 :             + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
     572             :             "\nCreate the signature\n"
     573          26 :             + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
     574             :             "\nVerify the signature\n"
     575          26 :             + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
     576             :             "\nAs a JSON-RPC call\n"
     577          26 :             + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
     578             :                 },
     579          26 :             }.Check(request);
     580             : 
     581          22 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     582          22 :     if (!wallet) return NullUniValue;
     583          22 :     const CWallet* const pwallet = wallet.get();
     584             : 
     585          22 :     LOCK(pwallet->cs_wallet);
     586             : 
     587          22 :     EnsureWalletIsUnlocked(pwallet);
     588             : 
     589          12 :     std::string strAddress = request.params[0].get_str();
     590          12 :     std::string strMessage = request.params[1].get_str();
     591             : 
     592          12 :     CTxDestination dest = DecodeDestination(strAddress);
     593          12 :     if (!IsValidDestination(dest)) {
     594           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
     595             :     }
     596             : 
     597          12 :     const PKHash *pkhash = boost::get<PKHash>(&dest);
     598          12 :     if (!pkhash) {
     599           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
     600             :     }
     601             : 
     602          12 :     std::string signature;
     603          12 :     SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature);
     604          12 :     if (err == SigningResult::SIGNING_FAILED) {
     605           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err));
     606          12 :     } else if (err != SigningResult::OK){
     607           0 :         throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err));
     608             :     }
     609             : 
     610          12 :     return signature;
     611          42 : }
     612             : 
     613          44 : static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
     614             : {
     615          44 :     std::set<CTxDestination> address_set;
     616             : 
     617          44 :     if (by_label) {
     618             :         // Get the set of addresses assigned to label
     619          30 :         std::string label = LabelFromValue(params[0]);
     620          30 :         address_set = wallet.GetLabelAddresses(label);
     621          30 :     } else {
     622             :         // Get the address
     623          14 :         CTxDestination dest = DecodeDestination(params[0].get_str());
     624          14 :         if (!IsValidDestination(dest)) {
     625           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
     626             :         }
     627          14 :         CScript script_pub_key = GetScriptForDestination(dest);
     628          14 :         if (!wallet.IsMine(script_pub_key)) {
     629           1 :             throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
     630             :         }
     631          13 :         address_set.insert(dest);
     632          14 :     }
     633             : 
     634             :     // Minimum confirmations
     635             :     int min_depth = 1;
     636          43 :     if (!params[1].isNull())
     637           1 :         min_depth = params[1].get_int();
     638             : 
     639             :     // Tally
     640        7815 :     CAmount amount = 0;
     641        3929 :     for (const std::pair<const uint256, CWalletTx>& wtx_pair : wallet.mapWallet) {
     642        3886 :         const CWalletTx& wtx = wtx_pair.second;
     643        3886 :         if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx) || wtx.GetDepthInMainChain() < min_depth) {
     644        3634 :             continue;
     645             :         }
     646             : 
     647         726 :         for (const CTxOut& txout : wtx.tx->vout) {
     648         474 :             CTxDestination address;
     649         474 :             if (ExtractDestination(txout.scriptPubKey, address) && wallet.IsMine(address) && address_set.count(address)) {
     650          52 :                 amount += txout.nValue;
     651          52 :             }
     652         474 :         }
     653         504 :     }
     654             : 
     655             :     return amount;
     656          45 : }
     657             : 
     658             : 
     659          18 : static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
     660             : {
     661          73 :             RPCHelpMan{"getreceivedbyaddress",
     662          18 :                 "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n",
     663          58 :                 {
     664          18 :                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."},
     665          18 :                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
     666             :                 },
     667          18 :                 RPCResult{
     668          18 :                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address."
     669             :                 },
     670          18 :                 RPCExamples{
     671          18 :             "\nThe amount from transactions with at least 1 confirmation\n"
     672          18 :             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
     673             :             "\nThe amount including unconfirmed transactions, zero confirmations\n"
     674          18 :             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0") +
     675             :             "\nThe amount with at least 6 confirmations\n"
     676          18 :             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6") +
     677             :             "\nAs a JSON-RPC call\n"
     678          18 :             + HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6")
     679             :                 },
     680          18 :             }.Check(request);
     681             : 
     682          14 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     683          14 :     if (!wallet) return NullUniValue;
     684          14 :     const CWallet* const pwallet = wallet.get();
     685             : 
     686             :     // Make sure the results are valid at least up to the most recent block
     687             :     // the user could have gotten from another RPC command prior to now
     688          14 :     pwallet->BlockUntilSyncedToCurrentChain();
     689             : 
     690          14 :     LOCK(pwallet->cs_wallet);
     691             : 
     692          14 :     return ValueFromAmount(GetReceived(*pwallet, request.params, /* by_label */ false));
     693          39 : }
     694             : 
     695             : 
     696          34 : static UniValue getreceivedbylabel(const JSONRPCRequest& request)
     697             : {
     698         136 :             RPCHelpMan{"getreceivedbylabel",
     699          34 :                 "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n",
     700         106 :                 {
     701          34 :                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."},
     702          34 :                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
     703             :                 },
     704          34 :                 RPCResult{
     705          34 :                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this label."
     706             :                 },
     707          34 :                 RPCExamples{
     708          34 :             "\nAmount received by the default label with at least 1 confirmation\n"
     709          34 :             + HelpExampleCli("getreceivedbylabel", "\"\"") +
     710             :             "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n"
     711          34 :             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
     712             :             "\nThe amount with at least 6 confirmations\n"
     713          34 :             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
     714             :             "\nAs a JSON-RPC call\n"
     715          34 :             + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
     716             :                 },
     717          34 :             }.Check(request);
     718             : 
     719          30 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     720          30 :     if (!wallet) return NullUniValue;
     721          30 :     const CWallet* const pwallet = wallet.get();
     722             : 
     723             :     // Make sure the results are valid at least up to the most recent block
     724             :     // the user could have gotten from another RPC command prior to now
     725          30 :     pwallet->BlockUntilSyncedToCurrentChain();
     726             : 
     727          30 :     LOCK(pwallet->cs_wallet);
     728             : 
     729          30 :     return ValueFromAmount(GetReceived(*pwallet, request.params, /* by_label */ true));
     730          54 : }
     731             : 
     732             : 
     733         364 : static UniValue getbalance(const JSONRPCRequest& request)
     734             : {
     735        2185 :             RPCHelpMan{"getbalance",
     736         364 :                 "\nReturns the total available balance.\n"
     737             :                 "The available balance is what the wallet considers currently spendable, and is\n"
     738             :                 "thus affected by options which limit spendability such as -spendzeroconfchange.\n",
     739        1824 :                 {
     740         364 :                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
     741         364 :                     {"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
     742         364 :                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also include balance in watch-only addresses (see 'importaddress')"},
     743         364 :                     {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
     744             :                 },
     745         364 :                 RPCResult{
     746         364 :                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet."
     747             :                 },
     748         364 :                 RPCExamples{
     749         364 :             "\nThe total amount in the wallet with 0 or more confirmations\n"
     750         364 :             + HelpExampleCli("getbalance", "") +
     751             :             "\nThe total amount in the wallet with at least 6 confirmations\n"
     752         364 :             + HelpExampleCli("getbalance", "\"*\" 6") +
     753             :             "\nAs a JSON-RPC call\n"
     754         364 :             + HelpExampleRpc("getbalance", "\"*\", 6")
     755             :                 },
     756         364 :             }.Check(request);
     757             : 
     758         360 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     759         360 :     if (!wallet) return NullUniValue;
     760         360 :     const CWallet* const pwallet = wallet.get();
     761             : 
     762             :     // Make sure the results are valid at least up to the most recent block
     763             :     // the user could have gotten from another RPC command prior to now
     764         360 :     pwallet->BlockUntilSyncedToCurrentChain();
     765             : 
     766         360 :     LOCK(pwallet->cs_wallet);
     767             : 
     768         360 :     const UniValue& dummy_value = request.params[0];
     769         360 :     if (!dummy_value.isNull() && dummy_value.get_str() != "*") {
     770           1 :         throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\".");
     771             :     }
     772             : 
     773             :     int min_depth = 0;
     774         359 :     if (!request.params[1].isNull()) {
     775          20 :         min_depth = request.params[1].get_int();
     776          20 :     }
     777             : 
     778         359 :     bool include_watchonly = ParseIncludeWatchonly(request.params[2], *pwallet);
     779             : 
     780         359 :     bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[3]);
     781             : 
     782         359 :     const auto bal = pwallet->GetBalance(min_depth, avoid_reuse);
     783             : 
     784         359 :     return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
     785         388 : }
     786             : 
     787           8 : static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
     788             : {
     789          24 :             RPCHelpMan{"getunconfirmedbalance",
     790           8 :                 "DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
     791           8 :                 {},
     792           8 :                 RPCResult{RPCResult::Type::NUM, "", "The balance"},
     793           8 :                 RPCExamples{""},
     794           8 :             }.Check(request);
     795             : 
     796           4 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     797           4 :     if (!wallet) return NullUniValue;
     798           4 :     const CWallet* const pwallet = wallet.get();
     799             : 
     800             :     // Make sure the results are valid at least up to the most recent block
     801             :     // the user could have gotten from another RPC command prior to now
     802           4 :     pwallet->BlockUntilSyncedToCurrentChain();
     803             : 
     804           4 :     LOCK(pwallet->cs_wallet);
     805             : 
     806           4 :     return ValueFromAmount(pwallet->GetBalance().m_mine_untrusted_pending);
     807           8 : }
     808             : 
     809             : 
     810         121 : static UniValue sendmany(const JSONRPCRequest& request)
     811             : {
     812        1223 :     RPCHelpMan{"sendmany",
     813         121 :                 "\nSend multiple times. Amounts are double-precision floating point numbers." +
     814             :         HELP_REQUIRING_PASSPHRASE,
     815        1109 :                 {
     816         121 :                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", "\"\""},
     817         242 :                     {"amounts", RPCArg::Type::OBJ, RPCArg::Optional::NO, "The addresses and amounts",
     818         242 :                         {
     819         121 :                             {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
     820             :                         },
     821             :                     },
     822         121 :                     {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"},
     823         121 :                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"},
     824         242 :                     {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The addresses.\n"
     825             :             "                           The fee will be equally deducted from the amount of each selected address.\n"
     826             :             "                           Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
     827             :             "                           If no addresses are specified here, the sender pays the fee.",
     828         242 :                         {
     829         121 :                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
     830             :                         },
     831             :                     },
     832         121 :                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
     833         121 :                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
     834         242 :                     {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
     835         121 :             "       \"" + FeeModes("\"\n\"") + "\""},
     836             :                 },
     837         121 :                  RPCResult{
     838         121 :                      RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
     839             :             "the number of addresses."
     840             :                  },
     841         121 :                 RPCExamples{
     842         121 :             "\nSend two amounts to two different addresses:\n"
     843         121 :             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\"") +
     844             :             "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
     845         121 :             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 6 \"testing\"") +
     846             :             "\nSend two amounts to two different addresses, subtract fee from amount:\n"
     847         121 :             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 1 \"\" \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
     848             :             "\nAs a JSON-RPC call\n"
     849         121 :             + HelpExampleRpc("sendmany", "\"\", {\"" + EXAMPLE_ADDRESS[0] + "\":0.01,\"" + EXAMPLE_ADDRESS[1] + "\":0.02}, 6, \"testing\"")
     850             :                 },
     851         121 :     }.Check(request);
     852             : 
     853         117 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     854         117 :     if (!wallet) return NullUniValue;
     855         117 :     CWallet* const pwallet = wallet.get();
     856             : 
     857             :     // Make sure the results are valid at least up to the most recent block
     858             :     // the user could have gotten from another RPC command prior to now
     859         117 :     pwallet->BlockUntilSyncedToCurrentChain();
     860             : 
     861         117 :     LOCK(pwallet->cs_wallet);
     862             : 
     863         117 :     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
     864           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
     865             :     }
     866         117 :     UniValue sendTo = request.params[1].get_obj();
     867             : 
     868         117 :     mapValue_t mapValue;
     869         117 :     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
     870           0 :         mapValue["comment"] = request.params[3].get_str();
     871             : 
     872         117 :     UniValue subtractFeeFromAmount(UniValue::VARR);
     873         117 :     if (!request.params[4].isNull())
     874           6 :         subtractFeeFromAmount = request.params[4].get_array();
     875             : 
     876         117 :     CCoinControl coin_control;
     877         117 :     if (!request.params[5].isNull()) {
     878           0 :         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
     879           0 :     }
     880             : 
     881         117 :     SetFeeEstimateMode(pwallet, coin_control, request.params[7], request.params[6]);
     882             : 
     883         109 :     std::vector<CRecipient> recipients;
     884         109 :     ParseRecipients(sendTo, subtractFeeFromAmount, recipients);
     885             : 
     886         109 :     return SendMoney(pwallet, coin_control, recipients, std::move(mapValue));
     887         181 : }
     888             : 
     889         123 : static UniValue addmultisigaddress(const JSONRPCRequest& request)
     890             : {
     891         988 :             RPCHelpMan{"addmultisigaddress",
     892         123 :                 "\nAdd an nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
     893             :                 "Each key is a Bitcoin address or hex-encoded public key.\n"
     894             :                 "This functionality is only intended for use with non-watchonly addresses.\n"
     895             :                 "See `importaddress` for watchonly p2sh address support.\n"
     896             :                 "If 'label' is specified, assign address to that label.\n",
     897         627 :                 {
     898         123 :                     {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."},
     899         246 :                     {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The bitcoin addresses or hex-encoded public keys",
     900         246 :                         {
     901         123 :                             {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address or hex-encoded public key"},
     902             :                         },
     903             :                         },
     904         123 :                     {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."},
     905         123 :                     {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
     906             :                 },
     907         123 :                 RPCResult{
     908         123 :                     RPCResult::Type::OBJ, "", "",
     909         496 :                     {
     910         123 :                         {RPCResult::Type::STR, "address", "The value of the new multisig address"},
     911         123 :                         {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script"},
     912         123 :                         {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig"},
     913             :                     }
     914             :                 },
     915         123 :                 RPCExamples{
     916         123 :             "\nAdd a multisig address from 2 addresses\n"
     917         123 :             + HelpExampleCli("addmultisigaddress", "2 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
     918             :             "\nAs a JSON-RPC call\n"
     919         123 :             + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
     920             :                 },
     921         123 :             }.Check(request);
     922             : 
     923         119 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
     924         119 :     if (!wallet) return NullUniValue;
     925         119 :     CWallet* const pwallet = wallet.get();
     926             : 
     927         119 :     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
     928             : 
     929         118 :     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
     930             : 
     931         118 :     std::string label;
     932         118 :     if (!request.params[2].isNull())
     933          34 :         label = LabelFromValue(request.params[2]);
     934             : 
     935         118 :     int required = request.params[0].get_int();
     936             : 
     937             :     // Get the public keys
     938         118 :     const UniValue& keys_or_addrs = request.params[1].get_array();
     939         118 :     std::vector<CPubKey> pubkeys;
     940         431 :     for (unsigned int i = 0; i < keys_or_addrs.size(); ++i) {
     941         313 :         if (IsHex(keys_or_addrs[i].get_str()) && (keys_or_addrs[i].get_str().length() == 66 || keys_or_addrs[i].get_str().length() == 130)) {
     942         171 :             pubkeys.push_back(HexToPubKey(keys_or_addrs[i].get_str()));
     943         171 :         } else {
     944         142 :             pubkeys.push_back(AddrToPubKey(spk_man, keys_or_addrs[i].get_str()));
     945             :         }
     946             :     }
     947             : 
     948         116 :     OutputType output_type = pwallet->m_default_address_type;
     949         116 :     if (!request.params[3].isNull()) {
     950          42 :         if (!ParseOutputType(request.params[3].get_str(), output_type)) {
     951           1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
     952             :         }
     953             :     }
     954             : 
     955             :     // Construct using pay-to-script-hash:
     956         115 :     CScript inner;
     957         115 :     CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, spk_man, inner);
     958         115 :     pwallet->SetAddressBook(dest, label, "send");
     959             : 
     960             :     // Make the descriptor
     961         115 :     std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), spk_man);
     962             : 
     963         115 :     UniValue result(UniValue::VOBJ);
     964         115 :     result.pushKV("address", EncodeDestination(dest));
     965         115 :     result.pushKV("redeemScript", HexStr(inner));
     966         115 :     result.pushKV("descriptor", descriptor->ToString());
     967         115 :     return result;
     968         169 : }
     969             : 
     970         500 : struct tallyitem
     971             : {
     972         250 :     CAmount nAmount{0};
     973         250 :     int nConf{std::numeric_limits<int>::max()};
     974             :     std::vector<uint256> txids;
     975         250 :     bool fIsWatchonly{false};
     976         500 :     tallyitem()
     977         250 :     {
     978         500 :     }
     979             : };
     980             : 
     981         350 : static UniValue ListReceived(const CWallet* const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
     982             : {
     983             :     // Minimum confirmations
     984             :     int nMinDepth = 1;
     985         350 :     if (!params[0].isNull())
     986         337 :         nMinDepth = params[0].get_int();
     987             : 
     988             :     // Whether to include empty labels
     989             :     bool fIncludeEmpty = false;
     990         350 :     if (!params[1].isNull())
     991          11 :         fIncludeEmpty = params[1].get_bool();
     992             : 
     993             :     isminefilter filter = ISMINE_SPENDABLE;
     994             : 
     995         350 :     if (ParseIncludeWatchonly(params[2], *pwallet)) {
     996             :         filter |= ISMINE_WATCH_ONLY;
     997         337 :     }
     998             : 
     999             :     bool has_filtered_address = false;
    1000         350 :     CTxDestination filtered_address = CNoDestination();
    1001         350 :     if (!by_label && params.size() > 3) {
    1002         330 :         if (!IsValidDestinationString(params[3].get_str())) {
    1003           1 :             throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
    1004             :         }
    1005         329 :         filtered_address = DecodeDestination(params[3].get_str());
    1006             :         has_filtered_address = true;
    1007         329 :     }
    1008             : 
    1009             :     // Tally
    1010         349 :     std::map<CTxDestination, tallyitem> mapTally;
    1011       18998 :     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
    1012       18649 :         const CWalletTx& wtx = pairWtx.second;
    1013             : 
    1014       18649 :         if (wtx.IsCoinBase() || !pwallet->chain().checkFinalTx(*wtx.tx)) {
    1015        9106 :             continue;
    1016             :         }
    1017             : 
    1018        9543 :         int nDepth = wtx.GetDepthInMainChain();
    1019        9543 :         if (nDepth < nMinDepth)
    1020           3 :             continue;
    1021             : 
    1022       28620 :         for (const CTxOut& txout : wtx.tx->vout)
    1023             :         {
    1024       19080 :             CTxDestination address;
    1025       19080 :             if (!ExtractDestination(txout.scriptPubKey, address))
    1026           0 :                 continue;
    1027             : 
    1028       19080 :             if (has_filtered_address && !(filtered_address == address)) {
    1029       18750 :                 continue;
    1030             :             }
    1031             : 
    1032         330 :             isminefilter mine = pwallet->IsMine(address);
    1033         330 :             if(!(mine & filter))
    1034          32 :                 continue;
    1035             : 
    1036         298 :             tallyitem& item = mapTally[address];
    1037         298 :             item.nAmount += txout.nValue;
    1038         298 :             item.nConf = std::min(item.nConf, nDepth);
    1039         298 :             item.txids.push_back(wtx.GetHash());
    1040         298 :             if (mine & ISMINE_WATCH_ONLY)
    1041         184 :                 item.fIsWatchonly = true;
    1042       19378 :         }
    1043       19083 :     }
    1044             : 
    1045             :     // Reply
    1046         349 :     UniValue ret(UniValue::VARR);
    1047         349 :     std::map<std::string, tallyitem> label_tally;
    1048             : 
    1049             :     // Create m_address_book iterator
    1050             :     // If we aren't filtering, go from begin() to end()
    1051         349 :     auto start = pwallet->m_address_book.begin();
    1052         349 :     auto end = pwallet->m_address_book.end();
    1053             :     // If we are filtering, find() the applicable entry
    1054         349 :     if (has_filtered_address) {
    1055         329 :         start = pwallet->m_address_book.find(filtered_address);
    1056         329 :         if (start != end) {
    1057         328 :             end = std::next(start);
    1058         328 :         }
    1059             :     }
    1060             : 
    1061         793 :     for (auto item_it = start; item_it != end; ++item_it)
    1062             :     {
    1063         444 :         if (item_it->second.IsChange()) continue;
    1064         444 :         const CTxDestination& address = item_it->first;
    1065         444 :         const std::string& label = item_it->second.GetLabel();
    1066         444 :         auto it = mapTally.find(address);
    1067         444 :         if (it == mapTally.end() && !fIncludeEmpty)
    1068         181 :             continue;
    1069             : 
    1070         263 :         CAmount nAmount = 0;
    1071         263 :         int nConf = std::numeric_limits<int>::max();
    1072             :         bool fIsWatchonly = false;
    1073         263 :         if (it != mapTally.end())
    1074             :         {
    1075         242 :             nAmount = (*it).second.nAmount;
    1076         242 :             nConf = (*it).second.nConf;
    1077         242 :             fIsWatchonly = (*it).second.fIsWatchonly;
    1078         242 :         }
    1079             : 
    1080         263 :         if (by_label)
    1081             :         {
    1082          20 :             tallyitem& _item = label_tally[label];
    1083          20 :             _item.nAmount += nAmount;
    1084          20 :             _item.nConf = std::min(_item.nConf, nConf);
    1085          20 :             _item.fIsWatchonly = fIsWatchonly;
    1086          20 :         }
    1087             :         else
    1088             :         {
    1089         243 :             UniValue obj(UniValue::VOBJ);
    1090         243 :             if(fIsWatchonly)
    1091         146 :                 obj.pushKV("involvesWatchonly", true);
    1092         243 :             obj.pushKV("address",       EncodeDestination(address));
    1093         243 :             obj.pushKV("amount",        ValueFromAmount(nAmount));
    1094         243 :             obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
    1095         243 :             obj.pushKV("label", label);
    1096         243 :             UniValue transactions(UniValue::VARR);
    1097         243 :             if (it != mapTally.end())
    1098             :             {
    1099         510 :                 for (const uint256& _item : (*it).second.txids)
    1100             :                 {
    1101         282 :                     transactions.push_back(_item.GetHex());
    1102             :                 }
    1103         228 :             }
    1104         243 :             obj.pushKV("txids", transactions);
    1105         243 :             ret.push_back(obj);
    1106         243 :         }
    1107         444 :     }
    1108             : 
    1109         349 :     if (by_label)
    1110             :     {
    1111          16 :         for (const auto& entry : label_tally)
    1112             :         {
    1113           8 :             CAmount nAmount = entry.second.nAmount;
    1114           8 :             int nConf = entry.second.nConf;
    1115           8 :             UniValue obj(UniValue::VOBJ);
    1116           8 :             if (entry.second.fIsWatchonly)
    1117           2 :                 obj.pushKV("involvesWatchonly", true);
    1118           8 :             obj.pushKV("amount",        ValueFromAmount(nAmount));
    1119           8 :             obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
    1120           8 :             obj.pushKV("label",         entry.first);
    1121           8 :             ret.push_back(obj);
    1122           8 :         }
    1123           8 :     }
    1124             : 
    1125             :     return ret;
    1126         350 : }
    1127             : 
    1128         346 : static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
    1129             : {
    1130        3807 :             RPCHelpMan{"listreceivedbyaddress",
    1131         346 :                 "\nList balances by receiving address.\n",
    1132        1734 :                 {
    1133         346 :                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
    1134         346 :                     {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include addresses that haven't received any payments."},
    1135         346 :                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
    1136         346 :                     {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."},
    1137             :                 },
    1138         346 :                 RPCResult{
    1139         346 :                     RPCResult::Type::ARR, "", "",
    1140         692 :                     {
    1141         692 :                         {RPCResult::Type::OBJ, "", "",
    1142        2426 :                         {
    1143         346 :                             {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction"},
    1144         346 :                             {RPCResult::Type::STR, "address", "The receiving address"},
    1145         346 :                             {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received by the address"},
    1146         346 :                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
    1147         346 :                             {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
    1148         692 :                             {RPCResult::Type::ARR, "txids", "",
    1149         692 :                             {
    1150         346 :                                 {RPCResult::Type::STR_HEX, "txid", "The ids of transactions received with the address"},
    1151             :                             }},
    1152             :                         }},
    1153             :                     }
    1154             :                 },
    1155         346 :                 RPCExamples{
    1156         346 :                     HelpExampleCli("listreceivedbyaddress", "")
    1157         346 :             + HelpExampleCli("listreceivedbyaddress", "6 true")
    1158         346 :             + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
    1159         346 :             + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"" + EXAMPLE_ADDRESS[0] + "\"")
    1160             :                 },
    1161         346 :             }.Check(request);
    1162             : 
    1163         342 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1164         342 :     if (!wallet) return NullUniValue;
    1165         342 :     const CWallet* const pwallet = wallet.get();
    1166             : 
    1167             :     // Make sure the results are valid at least up to the most recent block
    1168             :     // the user could have gotten from another RPC command prior to now
    1169         342 :     pwallet->BlockUntilSyncedToCurrentChain();
    1170             : 
    1171         342 :     LOCK(pwallet->cs_wallet);
    1172             : 
    1173         342 :     return ListReceived(pwallet, request.params, false);
    1174         394 : }
    1175             : 
    1176          12 : static UniValue listreceivedbylabel(const JSONRPCRequest& request)
    1177             : {
    1178          96 :             RPCHelpMan{"listreceivedbylabel",
    1179          12 :                 "\nList received transactions by label.\n",
    1180          52 :                 {
    1181          12 :                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
    1182          12 :                     {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include labels that haven't received any payments."},
    1183          12 :                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
    1184             :                 },
    1185          12 :                 RPCResult{
    1186          12 :                     RPCResult::Type::ARR, "", "",
    1187          24 :                     {
    1188          24 :                         {RPCResult::Type::OBJ, "", "",
    1189          64 :                         {
    1190          12 :                             {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction"},
    1191          12 :                             {RPCResult::Type::STR_AMOUNT, "amount", "The total amount received by addresses with this label"},
    1192          12 :                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
    1193          12 :                             {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
    1194             :                         }},
    1195             :                     }
    1196             :                 },
    1197          12 :                 RPCExamples{
    1198          12 :                     HelpExampleCli("listreceivedbylabel", "")
    1199          12 :             + HelpExampleCli("listreceivedbylabel", "6 true")
    1200          12 :             + HelpExampleRpc("listreceivedbylabel", "6, true, true")
    1201             :                 },
    1202          12 :             }.Check(request);
    1203             : 
    1204           8 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1205           8 :     if (!wallet) return NullUniValue;
    1206           8 :     const CWallet* const pwallet = wallet.get();
    1207             : 
    1208             :     // Make sure the results are valid at least up to the most recent block
    1209             :     // the user could have gotten from another RPC command prior to now
    1210           8 :     pwallet->BlockUntilSyncedToCurrentChain();
    1211             : 
    1212           8 :     LOCK(pwallet->cs_wallet);
    1213             : 
    1214           8 :     return ListReceived(pwallet, request.params, true);
    1215          48 : }
    1216             : 
    1217        2147 : static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
    1218             : {
    1219        2147 :     if (IsValidDestination(dest)) {
    1220        2146 :         entry.pushKV("address", EncodeDestination(dest));
    1221        2146 :     }
    1222        2147 : }
    1223             : 
    1224             : /**
    1225             :  * List transactions based on the given criteria.
    1226             :  *
    1227             :  * @param  pwallet        The wallet.
    1228             :  * @param  wtx            The wallet transaction.
    1229             :  * @param  nMinDepth      The minimum confirmation depth.
    1230             :  * @param  fLong          Whether to include the JSON version of the transaction.
    1231             :  * @param  ret            The UniValue into which the result is stored.
    1232             :  * @param  filter_ismine  The "is mine" filter flags.
    1233             :  * @param  filter_label   Optional label string to filter incoming transactions.
    1234             :  */
    1235       19442 : static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
    1236             : {
    1237       19442 :     CAmount nFee;
    1238       19442 :     std::list<COutputEntry> listReceived;
    1239       19442 :     std::list<COutputEntry> listSent;
    1240             : 
    1241       19442 :     wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine);
    1242             : 
    1243       19442 :     bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
    1244             : 
    1245             :     // Sent
    1246       19442 :     if (!filter_label)
    1247             :     {
    1248        2100 :         for (const COutputEntry& s : listSent)
    1249             :         {
    1250         438 :             UniValue entry(UniValue::VOBJ);
    1251         438 :             if (involvesWatchonly || (pwallet->IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
    1252           9 :                 entry.pushKV("involvesWatchonly", true);
    1253           9 :             }
    1254         438 :             MaybePushAddress(entry, s.destination);
    1255         438 :             entry.pushKV("category", "send");
    1256         438 :             entry.pushKV("amount", ValueFromAmount(-s.amount));
    1257         438 :             const auto* address_book_entry = pwallet->FindAddressBookEntry(s.destination);
    1258         438 :             if (address_book_entry) {
    1259         173 :                 entry.pushKV("label", address_book_entry->GetLabel());
    1260         173 :             }
    1261         438 :             entry.pushKV("vout", s.vout);
    1262         438 :             entry.pushKV("fee", ValueFromAmount(-nFee));
    1263         438 :             if (fLong)
    1264         221 :                 WalletTxToJSON(pwallet->chain(), wtx, entry);
    1265         438 :             entry.pushKV("abandoned", wtx.isAbandoned());
    1266         438 :             ret.push_back(entry);
    1267         438 :         }
    1268        1662 :     }
    1269             : 
    1270             :     // Received
    1271       19442 :     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) {
    1272       38400 :         for (const COutputEntry& r : listReceived)
    1273             :         {
    1274       19213 :             std::string label;
    1275       19213 :             const auto* address_book_entry = pwallet->FindAddressBookEntry(r.destination);
    1276       19213 :             if (address_book_entry) {
    1277       19168 :                 label = address_book_entry->GetLabel();
    1278             :             }
    1279       19213 :             if (filter_label && label != *filter_label) {
    1280       17504 :                 continue;
    1281             :             }
    1282        1709 :             UniValue entry(UniValue::VOBJ);
    1283        1709 :             if (involvesWatchonly || (pwallet->IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
    1284         201 :                 entry.pushKV("involvesWatchonly", true);
    1285         201 :             }
    1286        1709 :             MaybePushAddress(entry, r.destination);
    1287        1709 :             if (wtx.IsCoinBase())
    1288             :             {
    1289        1132 :                 if (wtx.GetDepthInMainChain() < 1)
    1290         203 :                     entry.pushKV("category", "orphan");
    1291         929 :                 else if (wtx.IsImmatureCoinBase())
    1292         677 :                     entry.pushKV("category", "immature");
    1293             :                 else
    1294         252 :                     entry.pushKV("category", "generate");
    1295             :             }
    1296             :             else
    1297             :             {
    1298         577 :                 entry.pushKV("category", "receive");
    1299             :             }
    1300        1709 :             entry.pushKV("amount", ValueFromAmount(r.amount));
    1301        1709 :             if (address_book_entry) {
    1302        1664 :                 entry.pushKV("label", label);
    1303        1664 :             }
    1304        1709 :             entry.pushKV("vout", r.vout);
    1305        1709 :             if (fLong)
    1306        1570 :                 WalletTxToJSON(pwallet->chain(), wtx, entry);
    1307        1709 :             ret.push_back(entry);
    1308       19213 :         }
    1309       19187 :     }
    1310       19442 : }
    1311             : 
    1312         673 : static const std::vector<RPCResult> TransactionDescriptionString()
    1313             : {
    1314       16825 :     return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
    1315             :                "transaction conflicted that many blocks ago."},
    1316         673 :            {RPCResult::Type::BOOL, "generated", "Only present if transaction only input is a coinbase one."},
    1317         673 :            {RPCResult::Type::BOOL, "trusted", "Only present if we consider transaction to be trusted and so safe to spend from."},
    1318         673 :            {RPCResult::Type::STR_HEX, "blockhash", "The block hash containing the transaction."},
    1319         673 :            {RPCResult::Type::NUM, "blockheight", "The block height containing the transaction."},
    1320         673 :            {RPCResult::Type::NUM, "blockindex", "The index of the transaction in the block that includes it."},
    1321         673 :            {RPCResult::Type::NUM_TIME, "blocktime", "The block time expressed in " + UNIX_EPOCH_TIME + "."},
    1322         673 :            {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
    1323        1346 :            {RPCResult::Type::ARR, "walletconflicts", "Conflicting transaction ids.",
    1324        1346 :            {
    1325         673 :                {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
    1326             :            }},
    1327         673 :            {RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
    1328         673 :            {RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
    1329         673 :            {RPCResult::Type::STR, "comment", "If a comment is associated with the transaction, only present if not empty."},
    1330         673 :            {RPCResult::Type::STR, "bip125-replaceable", "(\"yes|no|unknown\") Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
    1331             :                "may be unknown for unconfirmed transactions not in the mempool"}};
    1332           0 : }
    1333             : 
    1334         398 : UniValue listtransactions(const JSONRPCRequest& request)
    1335             : {
    1336        4776 :             RPCHelpMan{"listtransactions",
    1337         398 :                 "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
    1338             :                 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
    1339        1994 :                 {
    1340         398 :                     {"label|dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n"
    1341             :                           "with the specified label, or \"*\" to disable filtering and return all transactions."},
    1342         398 :                     {"count", RPCArg::Type::NUM, /* default */ "10", "The number of transactions to return"},
    1343         398 :                     {"skip", RPCArg::Type::NUM, /* default */ "0", "The number of transactions to skip"},
    1344         398 :                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
    1345             :                 },
    1346         398 :                 RPCResult{
    1347         398 :                     RPCResult::Type::ARR, "", "",
    1348         796 :                     {
    1349        1194 :                         {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
    1350        3188 :                         {
    1351         398 :                             {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction."},
    1352         398 :                             {RPCResult::Type::STR, "address", "The bitcoin address of the transaction."},
    1353         398 :                             {RPCResult::Type::STR, "category", "The transaction category.\n"
    1354             :                                 "\"send\"                  Transactions sent.\n"
    1355             :                                 "\"receive\"               Non-coinbase transactions received.\n"
    1356             :                                 "\"generate\"              Coinbase transactions received with more than 100 confirmations.\n"
    1357             :                                 "\"immature\"              Coinbase transactions received with 100 or fewer confirmations.\n"
    1358             :                                 "\"orphan\"                Orphaned coinbase transactions received."},
    1359         398 :                             {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
    1360             :                                 "for all other categories"},
    1361         398 :                             {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
    1362         398 :                             {RPCResult::Type::NUM, "vout", "the vout value"},
    1363         398 :                             {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
    1364             :                                  "'send' category of transactions."},
    1365             :                         },
    1366         398 :                         TransactionDescriptionString()),
    1367         796 :                         {
    1368         398 :                             {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
    1369             :                                  "'send' category of transactions."},
    1370             :                         })},
    1371             :                     }
    1372             :                 },
    1373         398 :                 RPCExamples{
    1374         398 :             "\nList the most recent 10 transactions in the systems\n"
    1375         398 :             + HelpExampleCli("listtransactions", "") +
    1376             :             "\nList transactions 100 to 120\n"
    1377         398 :             + HelpExampleCli("listtransactions", "\"*\" 20 100") +
    1378             :             "\nAs a JSON-RPC call\n"
    1379         398 :             + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
    1380             :                 },
    1381         398 :             }.Check(request);
    1382             : 
    1383         394 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1384         394 :     if (!wallet) return NullUniValue;
    1385         394 :     const CWallet* const pwallet = wallet.get();
    1386             : 
    1387             :     // Make sure the results are valid at least up to the most recent block
    1388             :     // the user could have gotten from another RPC command prior to now
    1389         394 :     pwallet->BlockUntilSyncedToCurrentChain();
    1390             : 
    1391             :     const std::string* filter_label = nullptr;
    1392         394 :     if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
    1393         330 :         filter_label = &request.params[0].get_str();
    1394         330 :         if (filter_label->empty()) {
    1395           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
    1396             :         }
    1397             :     }
    1398             :     int nCount = 10;
    1399         394 :     if (!request.params[1].isNull())
    1400         340 :         nCount = request.params[1].get_int();
    1401             :     int nFrom = 0;
    1402         394 :     if (!request.params[2].isNull())
    1403           8 :         nFrom = request.params[2].get_int();
    1404         394 :     isminefilter filter = ISMINE_SPENDABLE;
    1405             : 
    1406         394 :     if (ParseIncludeWatchonly(request.params[3], *pwallet)) {
    1407         339 :         filter |= ISMINE_WATCH_ONLY;
    1408         339 :     }
    1409             : 
    1410         394 :     if (nCount < 0)
    1411           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
    1412         394 :     if (nFrom < 0)
    1413           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
    1414             : 
    1415         394 :     UniValue ret(UniValue::VARR);
    1416             : 
    1417             :     {
    1418         394 :         LOCK(pwallet->cs_wallet);
    1419             : 
    1420         394 :         const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
    1421             : 
    1422             :         // iterate backwards until we have nCount items to return:
    1423       19076 :         for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
    1424             :         {
    1425       18682 :             CWalletTx *const pwtx = (*it).second;
    1426       18682 :             ListTransactions(pwallet, *pwtx, 0, true, ret, filter, filter_label);
    1427       18682 :             if ((int)ret.size() >= (nCount+nFrom)) break;
    1428       18640 :         }
    1429         394 :     }
    1430             : 
    1431             :     // ret is newest to oldest
    1432             : 
    1433         394 :     if (nFrom > (int)ret.size())
    1434           0 :         nFrom = ret.size();
    1435         394 :     if ((nFrom + nCount) > (int)ret.size())
    1436         352 :         nCount = ret.size() - nFrom;
    1437             : 
    1438         394 :     const std::vector<UniValue>& txs = ret.getValues();
    1439         394 :     UniValue result{UniValue::VARR};
    1440         394 :     result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom }); // Return oldest to newest
    1441         394 :     return result;
    1442         446 : }
    1443             : 
    1444          31 : static UniValue listsinceblock(const JSONRPCRequest& request)
    1445             : {
    1446         470 :             RPCHelpMan{"listsinceblock",
    1447          31 :                 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
    1448             :                 "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
    1449             :                 "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
    1450         159 :                 {
    1451          31 :                     {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
    1452          31 :                     {"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
    1453          31 :                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
    1454          31 :                     {"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n"
    1455             :             "                                                           (not guaranteed to work on pruned nodes)"},
    1456             :                 },
    1457          31 :                 RPCResult{
    1458          31 :                     RPCResult::Type::OBJ, "", "",
    1459         160 :                     {
    1460          62 :                         {RPCResult::Type::ARR, "transactions", "",
    1461          62 :                         {
    1462          93 :                             {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
    1463         221 :                             {
    1464          31 :                                 {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction."},
    1465          31 :                                 {RPCResult::Type::STR, "address", "The bitcoin address of the transaction."},
    1466          31 :                                 {RPCResult::Type::STR, "category", "The transaction category.\n"
    1467             :                                     "\"send\"                  Transactions sent.\n"
    1468             :                                     "\"receive\"               Non-coinbase transactions received.\n"
    1469             :                                     "\"generate\"              Coinbase transactions received with more than 100 confirmations.\n"
    1470             :                                     "\"immature\"              Coinbase transactions received with 100 or fewer confirmations.\n"
    1471             :                                     "\"orphan\"                Orphaned coinbase transactions received."},
    1472          31 :                                 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
    1473             :                                     "for all other categories"},
    1474          31 :                                 {RPCResult::Type::NUM, "vout", "the vout value"},
    1475          31 :                                 {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
    1476             :                                      "'send' category of transactions."},
    1477             :                             },
    1478          31 :                             TransactionDescriptionString()),
    1479         128 :                             {
    1480          31 :                                 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
    1481             :                                      "'send' category of transactions."},
    1482          31 :                                 {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
    1483          31 :                                 {RPCResult::Type::STR, "to", "If a comment to is associated with the transaction."},
    1484             :                             })},
    1485             :                         }},
    1486          62 :                         {RPCResult::Type::ARR, "removed", "<structure is the same as \"transactions\" above, only present if include_removed=true>\n"
    1487             :                             "Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count."
    1488          31 :                         , {{RPCResult::Type::ELISION, "", ""},}},
    1489          31 :                         {RPCResult::Type::STR_HEX, "lastblock", "The hash of the block (target_confirmations-1) from the best block on the main chain, or the genesis hash if the referenced block does not exist yet. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones"},
    1490             :                     }
    1491             :                 },
    1492          31 :                 RPCExamples{
    1493          31 :                     HelpExampleCli("listsinceblock", "")
    1494          31 :             + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
    1495          31 :             + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
    1496             :                 },
    1497          31 :             }.Check(request);
    1498             : 
    1499          27 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
    1500          27 :     if (!pwallet) return NullUniValue;
    1501             : 
    1502          27 :     const CWallet& wallet = *pwallet;
    1503             :     // Make sure the results are valid at least up to the most recent block
    1504             :     // the user could have gotten from another RPC command prior to now
    1505          27 :     wallet.BlockUntilSyncedToCurrentChain();
    1506             : 
    1507          27 :     LOCK(wallet.cs_wallet);
    1508             : 
    1509             :     // The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
    1510          27 :     Optional<int> height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
    1511          27 :     Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
    1512          27 :     int target_confirms = 1;
    1513          27 :     isminefilter filter = ISMINE_SPENDABLE;
    1514             : 
    1515          27 :     uint256 blockId;
    1516          27 :     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
    1517          17 :         blockId = ParseHashV(request.params[0], "blockhash");
    1518          15 :         height = int{};
    1519          15 :         altheight = int{};
    1520          15 :         if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /* ancestor out */ FoundBlock().height(*height), /* blockId out */ FoundBlock().height(*altheight))) {
    1521           2 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
    1522             :         }
    1523             :     }
    1524             : 
    1525          23 :     if (!request.params[1].isNull()) {
    1526           3 :         target_confirms = request.params[1].get_int();
    1527             : 
    1528           3 :         if (target_confirms < 1) {
    1529           1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
    1530             :         }
    1531             :     }
    1532             : 
    1533          22 :     if (ParseIncludeWatchonly(request.params[2], wallet)) {
    1534           2 :         filter |= ISMINE_WATCH_ONLY;
    1535           2 :     }
    1536             : 
    1537          22 :     bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
    1538             : 
    1539          22 :     int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1;
    1540             : 
    1541          22 :     UniValue transactions(UniValue::VARR);
    1542             : 
    1543         898 :     for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
    1544         876 :         const CWalletTx& tx = pairWtx.second;
    1545             : 
    1546         876 :         if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
    1547         521 :             ListTransactions(&wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
    1548             :         }
    1549           0 :     }
    1550             : 
    1551             :     // when a reorg'd block is requested, we also list any relevant transactions
    1552             :     // in the blocks of the chain that was detached
    1553          22 :     UniValue removed(UniValue::VARR);
    1554          34 :     while (include_removed && altheight && *altheight > *height) {
    1555          12 :         CBlock block;
    1556          12 :         if (!wallet.chain().findBlock(blockId, FoundBlock().data(block)) || block.IsNull()) {
    1557           0 :             throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
    1558             :         }
    1559          26 :         for (const CTransactionRef& tx : block.vtx) {
    1560          14 :             auto it = wallet.mapWallet.find(tx->GetHash());
    1561          14 :             if (it != wallet.mapWallet.end()) {
    1562             :                 // We want all transactions regardless of confirmation count to appear here,
    1563             :                 // even negative confirmation ones, hence the big negative.
    1564           2 :                 ListTransactions(&wallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
    1565             :             }
    1566          14 :         }
    1567          12 :         blockId = block.hashPrevBlock;
    1568          12 :         --*altheight;
    1569          12 :     }
    1570             : 
    1571          22 :     uint256 lastblock;
    1572          22 :     target_confirms = std::min(target_confirms, wallet.GetLastBlockHeight() + 1);
    1573          22 :     CHECK_NONFATAL(wallet.chain().findAncestorByHeight(wallet.GetLastBlockHash(), wallet.GetLastBlockHeight() + 1 - target_confirms, FoundBlock().hash(lastblock)));
    1574             : 
    1575          22 :     UniValue ret(UniValue::VOBJ);
    1576          22 :     ret.pushKV("transactions", transactions);
    1577          22 :     if (include_removed) ret.pushKV("removed", removed);
    1578          22 :     ret.pushKV("lastblock", lastblock.GetHex());
    1579             : 
    1580          22 :     return ret;
    1581          95 : }
    1582             : 
    1583         244 : static UniValue gettransaction(const JSONRPCRequest& request)
    1584             : {
    1585        3663 :             RPCHelpMan{"gettransaction",
    1586         244 :                 "\nGet detailed information about in-wallet transaction <txid>\n",
    1587         980 :                 {
    1588         244 :                     {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
    1589         488 :                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false",
    1590         244 :                             "Whether to include watch-only addresses in balance calculation and details[]"},
    1591         488 :                     {"verbose", RPCArg::Type::BOOL, /* default */ "false",
    1592         244 :                             "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
    1593             :                 },
    1594         244 :                 RPCResult{
    1595         732 :                     RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
    1596         736 :                     {
    1597         244 :                         {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
    1598         244 :                         {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
    1599             :                                      "'send' category of transactions."},
    1600             :                     },
    1601         244 :                     TransactionDescriptionString()),
    1602         996 :                     {
    1603         488 :                         {RPCResult::Type::ARR, "details", "",
    1604         488 :                         {
    1605         488 :                             {RPCResult::Type::OBJ, "", "",
    1606        2200 :                             {
    1607         244 :                                 {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction."},
    1608         244 :                                 {RPCResult::Type::STR, "address", "The bitcoin address involved in the transaction."},
    1609         244 :                                 {RPCResult::Type::STR, "category", "The transaction category.\n"
    1610             :                                     "\"send\"                  Transactions sent.\n"
    1611             :                                     "\"receive\"               Non-coinbase transactions received.\n"
    1612             :                                     "\"generate\"              Coinbase transactions received with more than 100 confirmations.\n"
    1613             :                                     "\"immature\"              Coinbase transactions received with 100 or fewer confirmations.\n"
    1614             :                                     "\"orphan\"                Orphaned coinbase transactions received."},
    1615         244 :                                 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
    1616         244 :                                 {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
    1617         244 :                                 {RPCResult::Type::NUM, "vout", "the vout value"},
    1618         244 :                                 {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
    1619             :                                     "'send' category of transactions."},
    1620         244 :                                 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
    1621             :                                      "'send' category of transactions."},
    1622             :                             }},
    1623             :                         }},
    1624         244 :                         {RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"},
    1625         488 :                         {RPCResult::Type::OBJ, "decoded", "Optional, the decoded transaction (only present when `verbose` is passed)",
    1626         488 :                         {
    1627         244 :                             {RPCResult::Type::ELISION, "", "Equivalent to the RPC decoderawtransaction method, or the RPC getrawtransaction method when `verbose` is passed."},
    1628             :                         }},
    1629             :                     })
    1630             :                 },
    1631         244 :                 RPCExamples{
    1632         244 :                     HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    1633         244 :             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
    1634         244 :             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")
    1635         244 :             + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    1636             :                 },
    1637         244 :             }.Check(request);
    1638             : 
    1639         240 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1640         240 :     if (!wallet) return NullUniValue;
    1641         240 :     const CWallet* const pwallet = wallet.get();
    1642             : 
    1643             :     // Make sure the results are valid at least up to the most recent block
    1644             :     // the user could have gotten from another RPC command prior to now
    1645         240 :     pwallet->BlockUntilSyncedToCurrentChain();
    1646             : 
    1647         240 :     LOCK(pwallet->cs_wallet);
    1648             : 
    1649         240 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    1650             : 
    1651         240 :     isminefilter filter = ISMINE_SPENDABLE;
    1652             : 
    1653         240 :     if (ParseIncludeWatchonly(request.params[1], *pwallet)) {
    1654           9 :         filter |= ISMINE_WATCH_ONLY;
    1655           9 :     }
    1656             : 
    1657         240 :     bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
    1658             : 
    1659         240 :     UniValue entry(UniValue::VOBJ);
    1660         240 :     auto it = pwallet->mapWallet.find(hash);
    1661         240 :     if (it == pwallet->mapWallet.end()) {
    1662           3 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
    1663             :     }
    1664         237 :     const CWalletTx& wtx = it->second;
    1665             : 
    1666         237 :     CAmount nCredit = wtx.GetCredit(filter);
    1667         237 :     CAmount nDebit = wtx.GetDebit(filter);
    1668         237 :     CAmount nNet = nCredit - nDebit;
    1669         237 :     CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
    1670             : 
    1671         237 :     entry.pushKV("amount", ValueFromAmount(nNet - nFee));
    1672         237 :     if (wtx.IsFromMe(filter))
    1673         207 :         entry.pushKV("fee", ValueFromAmount(nFee));
    1674             : 
    1675         237 :     WalletTxToJSON(pwallet->chain(), wtx, entry);
    1676             : 
    1677         237 :     UniValue details(UniValue::VARR);
    1678         237 :     ListTransactions(pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
    1679         237 :     entry.pushKV("details", details);
    1680             : 
    1681         237 :     std::string strHex = EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags());
    1682         237 :     entry.pushKV("hex", strHex);
    1683             : 
    1684         237 :     if (verbose) {
    1685           3 :         UniValue decoded(UniValue::VOBJ);
    1686           3 :         TxToUniv(*wtx.tx, uint256(), decoded, false);
    1687           3 :         entry.pushKV("decoded", decoded);
    1688           3 :     }
    1689             : 
    1690         237 :     return entry;
    1691         304 : }
    1692             : 
    1693          12 : static UniValue abandontransaction(const JSONRPCRequest& request)
    1694             : {
    1695          39 :             RPCHelpMan{"abandontransaction",
    1696          12 :                 "\nMark in-wallet transaction <txid> as abandoned\n"
    1697             :                 "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
    1698             :                 "for their inputs to be respent.  It can be used to replace \"stuck\" or evicted transactions.\n"
    1699             :                 "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
    1700             :                 "It has no effect on transactions which are already abandoned.\n",
    1701          24 :                 {
    1702          12 :                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    1703             :                 },
    1704          12 :                 RPCResult{RPCResult::Type::NONE, "", ""},
    1705          12 :                 RPCExamples{
    1706          12 :                     HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    1707          12 :             + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
    1708             :                 },
    1709          12 :             }.Check(request);
    1710             : 
    1711           8 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1712           8 :     if (!wallet) return NullUniValue;
    1713           8 :     CWallet* const pwallet = wallet.get();
    1714             : 
    1715             :     // Make sure the results are valid at least up to the most recent block
    1716             :     // the user could have gotten from another RPC command prior to now
    1717           8 :     pwallet->BlockUntilSyncedToCurrentChain();
    1718             : 
    1719           8 :     LOCK(pwallet->cs_wallet);
    1720             : 
    1721           8 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    1722             : 
    1723           8 :     if (!pwallet->mapWallet.count(hash)) {
    1724           1 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
    1725             :     }
    1726           7 :     if (!pwallet->AbandonTransaction(hash)) {
    1727           2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
    1728             :     }
    1729             : 
    1730           5 :     return NullUniValue;
    1731          24 : }
    1732             : 
    1733             : 
    1734          32 : static UniValue backupwallet(const JSONRPCRequest& request)
    1735             : {
    1736         100 :             RPCHelpMan{"backupwallet",
    1737          32 :                 "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
    1738          64 :                 {
    1739          32 :                     {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"},
    1740             :                 },
    1741          32 :                 RPCResult{RPCResult::Type::NONE, "", ""},
    1742          32 :                 RPCExamples{
    1743          32 :                     HelpExampleCli("backupwallet", "\"backup.dat\"")
    1744          32 :             + HelpExampleRpc("backupwallet", "\"backup.dat\"")
    1745             :                 },
    1746          32 :             }.Check(request);
    1747             : 
    1748          28 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1749          28 :     if (!wallet) return NullUniValue;
    1750          28 :     const CWallet* const pwallet = wallet.get();
    1751             : 
    1752             :     // Make sure the results are valid at least up to the most recent block
    1753             :     // the user could have gotten from another RPC command prior to now
    1754          28 :     pwallet->BlockUntilSyncedToCurrentChain();
    1755             : 
    1756          28 :     LOCK(pwallet->cs_wallet);
    1757             : 
    1758          28 :     std::string strDest = request.params[0].get_str();
    1759          28 :     if (!pwallet->BackupWallet(strDest)) {
    1760           4 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
    1761             :     }
    1762             : 
    1763          24 :     return NullUniValue;
    1764          44 : }
    1765             : 
    1766             : 
    1767          18 : static UniValue keypoolrefill(const JSONRPCRequest& request)
    1768             : {
    1769          54 :             RPCHelpMan{"keypoolrefill",
    1770          18 :                 "\nFills the keypool."+
    1771             :         HELP_REQUIRING_PASSPHRASE,
    1772          36 :                 {
    1773          18 :                     {"newsize", RPCArg::Type::NUM, /* default */ "100", "The new keypool size"},
    1774             :                 },
    1775          18 :                 RPCResult{RPCResult::Type::NONE, "", ""},
    1776          18 :                 RPCExamples{
    1777          18 :                     HelpExampleCli("keypoolrefill", "")
    1778          18 :             + HelpExampleRpc("keypoolrefill", "")
    1779             :                 },
    1780          18 :             }.Check(request);
    1781             : 
    1782          14 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1783          14 :     if (!wallet) return NullUniValue;
    1784          14 :     CWallet* const pwallet = wallet.get();
    1785             : 
    1786          14 :     if (pwallet->IsLegacy() && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
    1787           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
    1788             :     }
    1789             : 
    1790          14 :     LOCK(pwallet->cs_wallet);
    1791             : 
    1792             :     // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
    1793             :     unsigned int kpSize = 0;
    1794          14 :     if (!request.params[0].isNull()) {
    1795          11 :         if (request.params[0].get_int() < 0)
    1796           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
    1797          11 :         kpSize = (unsigned int)request.params[0].get_int();
    1798          11 :     }
    1799             : 
    1800          14 :     EnsureWalletIsUnlocked(pwallet);
    1801          14 :     pwallet->TopUpKeyPool(kpSize);
    1802             : 
    1803          14 :     if (pwallet->GetKeyPoolSize() < kpSize) {
    1804           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
    1805             :     }
    1806             : 
    1807          14 :     return NullUniValue;
    1808          30 : }
    1809             : 
    1810             : 
    1811          57 : static UniValue walletpassphrase(const JSONRPCRequest& request)
    1812             : {
    1813         242 :             RPCHelpMan{"walletpassphrase",
    1814          57 :                 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
    1815             :                 "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
    1816             :             "\nNote:\n"
    1817             :             "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
    1818             :             "time that overrides the old one.\n",
    1819         175 :                 {
    1820          57 :                     {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"},
    1821          57 :                     {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
    1822             :                 },
    1823          57 :                 RPCResult{RPCResult::Type::NONE, "", ""},
    1824          57 :                 RPCExamples{
    1825          57 :             "\nUnlock the wallet for 60 seconds\n"
    1826          57 :             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
    1827             :             "\nLock the wallet again (before 60 seconds)\n"
    1828          57 :             + HelpExampleCli("walletlock", "") +
    1829             :             "\nAs a JSON-RPC call\n"
    1830          57 :             + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
    1831             :                 },
    1832          57 :             }.Check(request);
    1833             : 
    1834          53 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1835          53 :     if (!wallet) return NullUniValue;
    1836          53 :     CWallet* const pwallet = wallet.get();
    1837             : 
    1838             :     int64_t nSleepTime;
    1839             :     int64_t relock_time;
    1840             :     // Prevent concurrent calls to walletpassphrase with the same wallet.
    1841          53 :     LOCK(pwallet->m_unlock_mutex);
    1842             :     {
    1843          53 :         LOCK(pwallet->cs_wallet);
    1844             : 
    1845          53 :         if (!pwallet->IsCrypted()) {
    1846           6 :             throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
    1847             :         }
    1848             : 
    1849             :         // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
    1850          47 :         SecureString strWalletPass;
    1851          47 :         strWalletPass.reserve(100);
    1852             :         // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    1853             :         // Alternately, find a way to make request.params[0] mlock()'d to begin with.
    1854          47 :         strWalletPass = request.params[0].get_str().c_str();
    1855             : 
    1856             :         // Get the timeout
    1857          47 :         nSleepTime = request.params[1].get_int64();
    1858             :         // Timeout cannot be negative, otherwise it will relock immediately
    1859          47 :         if (nSleepTime < 0) {
    1860           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
    1861             :         }
    1862             :         // Clamp timeout
    1863             :         constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
    1864          45 :         if (nSleepTime > MAX_SLEEP_TIME) {
    1865             :             nSleepTime = MAX_SLEEP_TIME;
    1866           2 :         }
    1867             : 
    1868          45 :         if (strWalletPass.empty()) {
    1869           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
    1870             :         }
    1871             : 
    1872          43 :         if (!pwallet->Unlock(strWalletPass)) {
    1873           4 :             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
    1874             :         }
    1875             : 
    1876          39 :         pwallet->TopUpKeyPool();
    1877             : 
    1878          39 :         pwallet->nRelockTime = GetTime() + nSleepTime;
    1879             :         relock_time = pwallet->nRelockTime;
    1880          53 :     }
    1881             : 
    1882             :     // rpcRunLater must be called without cs_wallet held otherwise a deadlock
    1883             :     // can occur. The deadlock would happen when RPCRunLater removes the
    1884             :     // previous timer (and waits for the callback to finish if already running)
    1885             :     // and the callback locks cs_wallet.
    1886          39 :     AssertLockNotHeld(wallet->cs_wallet);
    1887             :     // Keep a weak pointer to the wallet so that it is possible to unload the
    1888             :     // wallet before the following callback is called. If a valid shared pointer
    1889             :     // is acquired in the callback then the wallet is still loaded.
    1890          39 :     std::weak_ptr<CWallet> weak_wallet = wallet;
    1891         593 :     pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
    1892          14 :         if (auto shared_wallet = weak_wallet.lock()) {
    1893           6 :             LOCK(shared_wallet->cs_wallet);
    1894             :             // Skip if this is not the most recent rpcRunLater callback.
    1895           6 :             if (shared_wallet->nRelockTime != relock_time) return;
    1896           4 :             shared_wallet->Lock();
    1897           4 :             shared_wallet->nRelockTime = 0;
    1898           6 :         }
    1899           8 :     }, nSleepTime);
    1900             : 
    1901          39 :     return NullUniValue;
    1902          87 : }
    1903             : 
    1904             : 
    1905          10 : static UniValue walletpassphrasechange(const JSONRPCRequest& request)
    1906             : {
    1907          44 :             RPCHelpMan{"walletpassphrasechange",
    1908          10 :                 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n",
    1909          34 :                 {
    1910          10 :                     {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The current passphrase"},
    1911          10 :                     {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The new passphrase"},
    1912             :                 },
    1913          10 :                 RPCResult{RPCResult::Type::NONE, "", ""},
    1914          10 :                 RPCExamples{
    1915          10 :                     HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
    1916          10 :             + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
    1917             :                 },
    1918          10 :             }.Check(request);
    1919             : 
    1920           6 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1921           6 :     if (!wallet) return NullUniValue;
    1922           6 :     CWallet* const pwallet = wallet.get();
    1923             : 
    1924           6 :     LOCK(pwallet->cs_wallet);
    1925             : 
    1926           6 :     if (!pwallet->IsCrypted()) {
    1927           2 :         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
    1928             :     }
    1929             : 
    1930             :     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
    1931             :     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
    1932           4 :     SecureString strOldWalletPass;
    1933           4 :     strOldWalletPass.reserve(100);
    1934           4 :     strOldWalletPass = request.params[0].get_str().c_str();
    1935             : 
    1936           4 :     SecureString strNewWalletPass;
    1937           4 :     strNewWalletPass.reserve(100);
    1938           4 :     strNewWalletPass = request.params[1].get_str().c_str();
    1939             : 
    1940           4 :     if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
    1941           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
    1942             :     }
    1943             : 
    1944           2 :     if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
    1945           0 :         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
    1946             :     }
    1947             : 
    1948           2 :     return NullUniValue;
    1949          30 : }
    1950             : 
    1951             : 
    1952          15 : static UniValue walletlock(const JSONRPCRequest& request)
    1953             : {
    1954          45 :             RPCHelpMan{"walletlock",
    1955          15 :                 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
    1956             :                 "After calling this method, you will need to call walletpassphrase again\n"
    1957             :                 "before being able to call any methods which require the wallet to be unlocked.\n",
    1958          15 :                 {},
    1959          15 :                 RPCResult{RPCResult::Type::NONE, "", ""},
    1960          15 :                 RPCExamples{
    1961          15 :             "\nSet the passphrase for 2 minutes to perform a transaction\n"
    1962          15 :             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
    1963             :             "\nPerform a send (requires passphrase set)\n"
    1964          15 :             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 1.0") +
    1965             :             "\nClear the passphrase since we are done before 2 minutes is up\n"
    1966          15 :             + HelpExampleCli("walletlock", "") +
    1967             :             "\nAs a JSON-RPC call\n"
    1968          15 :             + HelpExampleRpc("walletlock", "")
    1969             :                 },
    1970          15 :             }.Check(request);
    1971             : 
    1972          11 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    1973          11 :     if (!wallet) return NullUniValue;
    1974          11 :     CWallet* const pwallet = wallet.get();
    1975             : 
    1976          11 :     LOCK(pwallet->cs_wallet);
    1977             : 
    1978          11 :     if (!pwallet->IsCrypted()) {
    1979           0 :         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
    1980             :     }
    1981             : 
    1982          11 :     pwallet->Lock();
    1983          11 :     pwallet->nRelockTime = 0;
    1984             : 
    1985          11 :     return NullUniValue;
    1986          15 : }
    1987             : 
    1988             : 
    1989          25 : static UniValue encryptwallet(const JSONRPCRequest& request)
    1990             : {
    1991          81 :             RPCHelpMan{"encryptwallet",
    1992          25 :                 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
    1993             :                 "After this, any calls that interact with private keys such as sending or signing \n"
    1994             :                 "will require the passphrase to be set prior the making these calls.\n"
    1995             :                 "Use the walletpassphrase call for this, and then walletlock call.\n"
    1996             :                 "If the wallet is already encrypted, use the walletpassphrasechange call.\n",
    1997          50 :                 {
    1998          25 :                     {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."},
    1999             :                 },
    2000          25 :                 RPCResult{RPCResult::Type::STR, "", "A string with further instructions"},
    2001          25 :                 RPCExamples{
    2002          25 :             "\nEncrypt your wallet\n"
    2003          25 :             + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
    2004             :             "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
    2005          25 :             + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
    2006             :             "\nNow we can do something like sign\n"
    2007          25 :             + HelpExampleCli("signmessage", "\"address\" \"test message\"") +
    2008             :             "\nNow lock the wallet again by removing the passphrase\n"
    2009          25 :             + HelpExampleCli("walletlock", "") +
    2010             :             "\nAs a JSON-RPC call\n"
    2011          25 :             + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
    2012             :                 },
    2013          25 :             }.Check(request);
    2014             : 
    2015          21 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    2016          21 :     if (!wallet) return NullUniValue;
    2017          21 :     CWallet* const pwallet = wallet.get();
    2018             : 
    2019          21 :     LOCK(pwallet->cs_wallet);
    2020             : 
    2021          21 :     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
    2022           2 :         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
    2023             :     }
    2024             : 
    2025          19 :     if (pwallet->IsCrypted()) {
    2026           2 :         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
    2027             :     }
    2028             : 
    2029             :     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    2030             :     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
    2031          17 :     SecureString strWalletPass;
    2032          17 :     strWalletPass.reserve(100);
    2033          17 :     strWalletPass = request.params[0].get_str().c_str();
    2034             : 
    2035          17 :     if (strWalletPass.empty()) {
    2036           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
    2037             :     }
    2038             : 
    2039          15 :     if (!pwallet->EncryptWallet(strWalletPass)) {
    2040           0 :         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
    2041             :     }
    2042             : 
    2043          15 :     return "wallet encrypted; The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
    2044          37 : }
    2045             : 
    2046          27 : static UniValue lockunspent(const JSONRPCRequest& request)
    2047             : {
    2048         149 :             RPCHelpMan{"lockunspent",
    2049          27 :                 "\nUpdates list of temporarily unspendable outputs.\n"
    2050             :                 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
    2051             :                 "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
    2052             :                 "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
    2053             :                 "Manually selected coins are automatically unlocked.\n"
    2054             :                 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
    2055             :                 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
    2056             :                 "Also see the listunspent call\n",
    2057          85 :                 {
    2058          27 :                     {"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"},
    2059          54 :                     {"transactions", RPCArg::Type::ARR, /* default */ "empty array", "The transaction outputs and within each, the txid (string) vout (numeric).",
    2060          54 :                         {
    2061          54 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    2062          85 :                                 {
    2063          27 :                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    2064          27 :                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    2065             :                                 },
    2066             :                             },
    2067             :                         },
    2068             :                     },
    2069             :                 },
    2070          27 :                 RPCResult{
    2071          27 :                     RPCResult::Type::BOOL, "", "Whether the command was successful or not"
    2072             :                 },
    2073          27 :                 RPCExamples{
    2074          27 :             "\nList the unspent transactions\n"
    2075          27 :             + HelpExampleCli("listunspent", "") +
    2076             :             "\nLock an unspent transaction\n"
    2077          27 :             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    2078             :             "\nList the locked transactions\n"
    2079          27 :             + HelpExampleCli("listlockunspent", "") +
    2080             :             "\nUnlock the transaction again\n"
    2081          27 :             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    2082             :             "\nAs a JSON-RPC call\n"
    2083          27 :             + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
    2084             :                 },
    2085          27 :             }.Check(request);
    2086             : 
    2087          23 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    2088          23 :     if (!wallet) return NullUniValue;
    2089          23 :     CWallet* const pwallet = wallet.get();
    2090             : 
    2091             :     // Make sure the results are valid at least up to the most recent block
    2092             :     // the user could have gotten from another RPC command prior to now
    2093          23 :     pwallet->BlockUntilSyncedToCurrentChain();
    2094             : 
    2095          23 :     LOCK(pwallet->cs_wallet);
    2096             : 
    2097          23 :     RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
    2098             : 
    2099          23 :     bool fUnlock = request.params[0].get_bool();
    2100             : 
    2101          23 :     if (request.params[1].isNull()) {
    2102           0 :         if (fUnlock)
    2103           0 :             pwallet->UnlockAllCoins();
    2104           0 :         return true;
    2105             :     }
    2106             : 
    2107          23 :     RPCTypeCheckArgument(request.params[1], UniValue::VARR);
    2108             : 
    2109          23 :     const UniValue& output_params = request.params[1];
    2110             : 
    2111             :     // Create and validate the COutPoints first.
    2112             : 
    2113          23 :     std::vector<COutPoint> outputs;
    2114          23 :     outputs.reserve(output_params.size());
    2115             : 
    2116          46 :     for (unsigned int idx = 0; idx < output_params.size(); idx++) {
    2117          23 :         const UniValue& o = output_params[idx].get_obj();
    2118             : 
    2119          46 :         RPCTypeCheckObj(o,
    2120          69 :             {
    2121          23 :                 {"txid", UniValueType(UniValue::VSTR)},
    2122          23 :                 {"vout", UniValueType(UniValue::VNUM)},
    2123             :             });
    2124             : 
    2125          23 :         const uint256 txid(ParseHashO(o, "txid"));
    2126          19 :         const int nOutput = find_value(o, "vout").get_int();
    2127          19 :         if (nOutput < 0) {
    2128           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
    2129             :         }
    2130             : 
    2131          19 :         const COutPoint outpt(txid, nOutput);
    2132             : 
    2133          19 :         const auto it = pwallet->mapWallet.find(outpt.hash);
    2134          19 :         if (it == pwallet->mapWallet.end()) {
    2135           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
    2136             :         }
    2137             : 
    2138          17 :         const CWalletTx& trans = it->second;
    2139             : 
    2140          17 :         if (outpt.n >= trans.tx->vout.size()) {
    2141           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
    2142             :         }
    2143             : 
    2144          15 :         if (pwallet->IsSpent(outpt.hash, outpt.n)) {
    2145           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
    2146             :         }
    2147             : 
    2148          13 :         const bool is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n);
    2149             : 
    2150          13 :         if (fUnlock && !is_locked) {
    2151           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
    2152             :         }
    2153             : 
    2154          11 :         if (!fUnlock && is_locked) {
    2155           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
    2156             :         }
    2157             : 
    2158           9 :         outputs.push_back(outpt);
    2159          23 :     }
    2160             : 
    2161             :     // Atomically set (un)locked status for the outputs.
    2162          18 :     for (const COutPoint& outpt : outputs) {
    2163           9 :         if (fUnlock) pwallet->UnlockCoin(outpt);
    2164           5 :         else pwallet->LockCoin(outpt);
    2165             :     }
    2166             : 
    2167           9 :     return true;
    2168          85 : }
    2169             : 
    2170          19 : static UniValue listlockunspent(const JSONRPCRequest& request)
    2171             : {
    2172          76 :             RPCHelpMan{"listlockunspent",
    2173          19 :                 "\nReturns list of temporarily unspendable outputs.\n"
    2174             :                 "See the lockunspent call to lock and unlock transactions for spending.\n",
    2175          19 :                 {},
    2176          19 :                 RPCResult{
    2177          19 :                     RPCResult::Type::ARR, "", "",
    2178          38 :                     {
    2179          38 :                         {RPCResult::Type::OBJ, "", "",
    2180          61 :                         {
    2181          19 :                             {RPCResult::Type::STR_HEX, "txid", "The transaction id locked"},
    2182          19 :                             {RPCResult::Type::NUM, "vout", "The vout value"},
    2183             :                         }},
    2184             :                     }
    2185             :                 },
    2186          19 :                 RPCExamples{
    2187          19 :             "\nList the unspent transactions\n"
    2188          19 :             + HelpExampleCli("listunspent", "") +
    2189             :             "\nLock an unspent transaction\n"
    2190          19 :             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    2191             :             "\nList the locked transactions\n"
    2192          19 :             + HelpExampleCli("listlockunspent", "") +
    2193             :             "\nUnlock the transaction again\n"
    2194          19 :             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
    2195             :             "\nAs a JSON-RPC call\n"
    2196          19 :             + HelpExampleRpc("listlockunspent", "")
    2197             :                 },
    2198          19 :             }.Check(request);
    2199             : 
    2200          15 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    2201          15 :     if (!wallet) return NullUniValue;
    2202          15 :     const CWallet* const pwallet = wallet.get();
    2203             : 
    2204          15 :     LOCK(pwallet->cs_wallet);
    2205             : 
    2206          15 :     std::vector<COutPoint> vOutpts;
    2207          15 :     pwallet->ListLockedCoins(vOutpts);
    2208             : 
    2209          15 :     UniValue ret(UniValue::VARR);
    2210             : 
    2211          22 :     for (const COutPoint& outpt : vOutpts) {
    2212           7 :         UniValue o(UniValue::VOBJ);
    2213             : 
    2214           7 :         o.pushKV("txid", outpt.hash.GetHex());
    2215           7 :         o.pushKV("vout", (int)outpt.n);
    2216           7 :         ret.push_back(o);
    2217           7 :     }
    2218             : 
    2219          15 :     return ret;
    2220          35 : }
    2221             : 
    2222          25 : static UniValue settxfee(const JSONRPCRequest& request)
    2223             : {
    2224          78 :             RPCHelpMan{"settxfee",
    2225          25 :                 "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n"
    2226             :                 "Can be deactivated by passing 0 as the fee. In that case automatic fee selection will be used by default.\n",
    2227          50 :                 {
    2228          25 :                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kB"},
    2229             :                 },
    2230          25 :                 RPCResult{
    2231          25 :                     RPCResult::Type::BOOL, "", "Returns true if successful"
    2232             :                 },
    2233          25 :                 RPCExamples{
    2234          25 :                     HelpExampleCli("settxfee", "0.00001")
    2235          25 :             + HelpExampleRpc("settxfee", "0.00001")
    2236             :                 },
    2237          25 :             }.Check(request);
    2238             : 
    2239          21 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    2240          21 :     if (!wallet) return NullUniValue;
    2241          21 :     CWallet* const pwallet = wallet.get();
    2242             : 
    2243          21 :     LOCK(pwallet->cs_wallet);
    2244             : 
    2245          21 :     CAmount nAmount = AmountFromValue(request.params[0]);
    2246          21 :     CFeeRate tx_fee_rate(nAmount, 1000);
    2247          21 :     CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
    2248          21 :     if (tx_fee_rate == CFeeRate(0)) {
    2249             :         // automatic selection
    2250          18 :     } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
    2251           1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
    2252          17 :     } else if (tx_fee_rate < pwallet->m_min_fee) {
    2253           1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
    2254          16 :     } else if (tx_fee_rate > max_tx_fee_rate) {
    2255           1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be more than wallet max tx fee (%s)", max_tx_fee_rate.ToString()));
    2256             :     }
    2257             : 
    2258          18 :     pwallet->m_pay_tx_fee = tx_fee_rate;
    2259          18 :     return true;
    2260          37 : }
    2261             : 
    2262         306 : static UniValue getbalances(const JSONRPCRequest& request)
    2263             : {
    2264        2754 :     RPCHelpMan{
    2265         306 :         "getbalances",
    2266         306 :         "Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
    2267         306 :         {},
    2268         306 :         RPCResult{
    2269         306 :             RPCResult::Type::OBJ, "", "",
    2270         930 :             {
    2271         612 :                 {RPCResult::Type::OBJ, "mine", "balances from outputs that the wallet can sign",
    2272        1534 :                 {
    2273         306 :                     {RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"},
    2274         306 :                     {RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
    2275         306 :                     {RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
    2276         306 :                     {RPCResult::Type::STR_AMOUNT, "used", "(only present if avoid_reuse is set) balance from coins sent to addresses that were previously spent from (potentially privacy violating)"},
    2277             :                 }},
    2278         612 :                 {RPCResult::Type::OBJ, "watchonly", "watchonly balances (not present if wallet does not watch anything)",
    2279        1228 :                 {
    2280         306 :                     {RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"},
    2281         306 :                     {RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
    2282         306 :                     {RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
    2283             :                 }},
    2284             :             }
    2285             :             },
    2286         306 :         RPCExamples{
    2287         612 :             HelpExampleCli("getbalances", "") +
    2288         306 :             HelpExampleRpc("getbalances", "")},
    2289         306 :     }.Check(request);
    2290             : 
    2291         302 :     std::shared_ptr<CWallet> const rpc_wallet = GetWalletForJSONRPCRequest(request);
    2292         302 :     if (!rpc_wallet) return NullUniValue;
    2293         298 :     CWallet& wallet = *rpc_wallet;
    2294             : 
    2295             :     // Make sure the results are valid at least up to the most recent block
    2296             :     // the user could have gotten from another RPC command prior to now
    2297         298 :     wallet.BlockUntilSyncedToCurrentChain();
    2298             : 
    2299         298 :     LOCK(wallet.cs_wallet);
    2300             : 
    2301         298 :     const auto bal = wallet.GetBalance();
    2302         298 :     UniValue balances{UniValue::VOBJ};
    2303             :     {
    2304         298 :         UniValue balances_mine{UniValue::VOBJ};
    2305         298 :         balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
    2306         298 :         balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
    2307         298 :         balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
    2308         298 :         if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
    2309             :             // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
    2310             :             // the total balance, and then subtract bal to get the reused address balance.
    2311          28 :             const auto full_bal = wallet.GetBalance(0, false);
    2312          28 :             balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
    2313          28 :         }
    2314         298 :         balances.pushKV("mine", balances_mine);
    2315         298 :     }
    2316         298 :     auto spk_man = wallet.GetLegacyScriptPubKeyMan();
    2317         298 :     if (spk_man && spk_man->HaveWatchOnly()) {
    2318           6 :         UniValue balances_watchonly{UniValue::VOBJ};
    2319           6 :         balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
    2320           6 :         balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
    2321           6 :         balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
    2322           6 :         balances.pushKV("watchonly", balances_watchonly);
    2323           6 :     }
    2324         298 :     return balances;
    2325         326 : }
    2326             : 
    2327        1086 : static UniValue getwalletinfo(const JSONRPCRequest& request)
    2328             : {
    2329       20634 :     RPCHelpMan{"getwalletinfo",
    2330        1086 :                 "Returns an object containing various wallet state info.\n",
    2331        1086 :                 {},
    2332        1086 :                 RPCResult{
    2333        1086 :                     RPCResult::Type::OBJ, "", "",
    2334        1086 :                     {
    2335       17388 :                         {
    2336        1086 :                         {RPCResult::Type::STR, "walletname", "the wallet name"},
    2337        1086 :                         {RPCResult::Type::NUM, "walletversion", "the wallet version"},
    2338        1086 :                         {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
    2339        1086 :                         {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
    2340        1086 :                         {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
    2341        1086 :                         {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
    2342        1086 :                         {RPCResult::Type::NUM_TIME, "keypoololdest", "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
    2343        1086 :                         {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
    2344        1086 :                         {RPCResult::Type::NUM, "keypoolsize_hd_internal", "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)"},
    2345        1086 :                         {RPCResult::Type::NUM_TIME, "unlocked_until", /* optional */ true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
    2346        1086 :                         {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB"},
    2347        1086 :                         {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "the Hash160 of the HD seed (only present when HD is enabled)"},
    2348        1086 :                         {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
    2349        1086 :                         {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
    2350        2172 :                         {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
    2351        3262 :                         {
    2352        1086 :                             {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
    2353        1086 :                             {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
    2354             :                         }},
    2355        1086 :                         {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
    2356             :                     }},
    2357             :                 },
    2358        1086 :                 RPCExamples{
    2359        1086 :                     HelpExampleCli("getwalletinfo", "")
    2360        1086 :             + HelpExampleRpc("getwalletinfo", "")
    2361             :                 },
    2362        1086 :     }.Check(request);
    2363             : 
    2364        1082 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    2365        1082 :     if (!wallet) return NullUniValue;
    2366        1068 :     const CWallet* const pwallet = wallet.get();
    2367             : 
    2368             :     // Make sure the results are valid at least up to the most recent block
    2369             :     // the user could have gotten from another RPC command prior to now
    2370        1068 :     pwallet->BlockUntilSyncedToCurrentChain();
    2371             : 
    2372        1068 :     LOCK(pwallet->cs_wallet);
    2373             : 
    2374        1068 :     UniValue obj(UniValue::VOBJ);
    2375             : 
    2376        1068 :     size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
    2377        1068 :     const auto bal = pwallet->GetBalance();
    2378        1068 :     int64_t kp_oldest = pwallet->GetOldestKeyPoolTime();
    2379        1068 :     obj.pushKV("walletname", pwallet->GetName());
    2380        1068 :     obj.pushKV("walletversion", pwallet->GetVersion());
    2381        1068 :     obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
    2382        1068 :     obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
    2383        1068 :     obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
    2384        1068 :     obj.pushKV("txcount",       (int)pwallet->mapWallet.size());
    2385        1068 :     if (kp_oldest > 0) {
    2386         956 :         obj.pushKV("keypoololdest", kp_oldest);
    2387         956 :     }
    2388        1068 :     obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
    2389             : 
    2390        1068 :     LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
    2391        1068 :     if (spk_man) {
    2392         949 :         CKeyID seed_id = spk_man->GetHDChain().seed_id;
    2393         949 :         if (!seed_id.IsNull()) {
    2394         869 :             obj.pushKV("hdseedid", seed_id.GetHex());
    2395         869 :         }
    2396         949 :     }
    2397             : 
    2398        1068 :     if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
    2399        1067 :         obj.pushKV("keypoolsize_hd_internal",   (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
    2400        1067 :     }
    2401        1068 :     if (pwallet->IsCrypted()) {
    2402          21 :         obj.pushKV("unlocked_until", pwallet->nRelockTime);
    2403          21 :     }
    2404        1068 :     obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
    2405        1068 :     obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
    2406        1068 :     obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
    2407        1068 :     if (pwallet->IsScanning()) {
    2408           0 :         UniValue scanning(UniValue::VOBJ);
    2409           0 :         scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
    2410           0 :         scanning.pushKV("progress", pwallet->ScanningProgress());
    2411           0 :         obj.pushKV("scanning", scanning);
    2412           0 :     } else {
    2413        1068 :         obj.pushKV("scanning", false);
    2414             :     }
    2415        1068 :     obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
    2416        1068 :     return obj;
    2417        1088 : }
    2418             : 
    2419          12 : static UniValue listwalletdir(const JSONRPCRequest& request)
    2420             : {
    2421          36 :             RPCHelpMan{"listwalletdir",
    2422          12 :                 "Returns a list of wallets in the wallet directory.\n",
    2423          12 :                 {},
    2424          12 :                 RPCResult{
    2425          12 :                     RPCResult::Type::OBJ, "", "",
    2426          24 :                     {
    2427          24 :                         {RPCResult::Type::ARR, "wallets", "",
    2428          24 :                         {
    2429          24 :                             {RPCResult::Type::OBJ, "", "",
    2430          24 :                             {
    2431          12 :                                 {RPCResult::Type::STR, "name", "The wallet name"},
    2432             :                             }},
    2433             :                         }},
    2434             :                     }
    2435             :                 },
    2436          12 :                 RPCExamples{
    2437          12 :                     HelpExampleCli("listwalletdir", "")
    2438          12 :             + HelpExampleRpc("listwalletdir", "")
    2439             :                 },
    2440          12 :             }.Check(request);
    2441             : 
    2442           8 :     UniValue wallets(UniValue::VARR);
    2443          70 :     for (const auto& path : ListWalletDir()) {
    2444          62 :         UniValue wallet(UniValue::VOBJ);
    2445          62 :         wallet.pushKV("name", path.string());
    2446          62 :         wallets.push_back(wallet);
    2447          62 :     }
    2448             : 
    2449           8 :     UniValue result(UniValue::VOBJ);
    2450           8 :     result.pushKV("wallets", wallets);
    2451             :     return result;
    2452          36 : }
    2453             : 
    2454          66 : static UniValue listwallets(const JSONRPCRequest& request)
    2455             : {
    2456         198 :             RPCHelpMan{"listwallets",
    2457          66 :                 "Returns a list of currently loaded wallets.\n"
    2458             :                 "For full information on the wallet, use \"getwalletinfo\"\n",
    2459          66 :                 {},
    2460          66 :                 RPCResult{
    2461          66 :                     RPCResult::Type::ARR, "", "",
    2462         132 :                     {
    2463          66 :                         {RPCResult::Type::STR, "walletname", "the wallet name"},
    2464             :                     }
    2465             :                 },
    2466          66 :                 RPCExamples{
    2467          66 :                     HelpExampleCli("listwallets", "")
    2468          66 :             + HelpExampleRpc("listwallets", "")
    2469             :                 },
    2470          66 :             }.Check(request);
    2471             : 
    2472          62 :     UniValue obj(UniValue::VARR);
    2473             : 
    2474         259 :     for (const std::shared_ptr<CWallet>& wallet : GetWallets()) {
    2475         197 :         LOCK(wallet->cs_wallet);
    2476         197 :         obj.push_back(wallet->GetName());
    2477         197 :     }
    2478             : 
    2479             :     return obj;
    2480          74 : }
    2481             : 
    2482         139 : static UniValue loadwallet(const JSONRPCRequest& request)
    2483             : {
    2484         717 :             RPCHelpMan{"loadwallet",
    2485         139 :                 "\nLoads a wallet from a wallet file or directory."
    2486             :                 "\nNote that all wallet command-line options used when starting bitcoind will be"
    2487             :                 "\napplied to the new wallet (eg -rescan, etc).\n",
    2488         421 :                 {
    2489         139 :                     {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
    2490         139 :                     {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
    2491             :                 },
    2492         139 :                 RPCResult{
    2493         139 :                     RPCResult::Type::OBJ, "", "",
    2494         421 :                     {
    2495         139 :                         {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
    2496         139 :                         {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
    2497             :                     }
    2498             :                 },
    2499         139 :                 RPCExamples{
    2500         139 :                     HelpExampleCli("loadwallet", "\"test.dat\"")
    2501         139 :             + HelpExampleRpc("loadwallet", "\"test.dat\"")
    2502             :                 },
    2503         139 :             }.Check(request);
    2504             : 
    2505         135 :     WalletContext& context = EnsureWalletContext(request.context);
    2506         135 :     const std::string name(request.params[0].get_str());
    2507             : 
    2508         135 :     DatabaseOptions options;
    2509         135 :     DatabaseStatus status;
    2510         135 :     options.require_existing = true;
    2511         135 :     bilingual_str error;
    2512         135 :     std::vector<bilingual_str> warnings;
    2513         135 :     Optional<bool> load_on_start = request.params[1].isNull() ? nullopt : Optional<bool>(request.params[1].get_bool());
    2514         135 :     std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, name, load_on_start, options, status, error, warnings);
    2515         135 :     if (!wallet) {
    2516             :         // Map bad format to not found, since bad format is returned when the
    2517             :         // wallet directory exists, but doesn't contain a data file.
    2518          22 :         RPCErrorCode code = status == DatabaseStatus::FAILED_NOT_FOUND || status == DatabaseStatus::FAILED_BAD_FORMAT ? RPC_WALLET_NOT_FOUND : RPC_WALLET_ERROR;
    2519          22 :         throw JSONRPCError(code, error.original);
    2520          22 :     }
    2521             : 
    2522         113 :     UniValue obj(UniValue::VOBJ);
    2523         113 :     obj.pushKV("name", wallet->GetName());
    2524         113 :     obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
    2525             : 
    2526             :     return obj;
    2527         163 : }
    2528             : 
    2529          14 : static UniValue setwalletflag(const JSONRPCRequest& request)
    2530             : {
    2531          14 :             std::string flags = "";
    2532          84 :             for (auto& it : WALLET_FLAG_MAP)
    2533          70 :                 if (it.second & MUTABLE_WALLET_FLAGS)
    2534          14 :                     flags += (flags == "" ? "" : ", ") + it.first;
    2535          84 :             RPCHelpMan{"setwalletflag",
    2536          14 :                 "\nChange the state of the given wallet flag for a wallet.\n",
    2537          46 :                 {
    2538          14 :                     {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
    2539          14 :                     {"value", RPCArg::Type::BOOL, /* default */ "true", "The new state."},
    2540             :                 },
    2541          14 :                 RPCResult{
    2542          14 :                     RPCResult::Type::OBJ, "", "",
    2543          60 :                     {
    2544          14 :                         {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
    2545          14 :                         {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
    2546          14 :                         {RPCResult::Type::STR, "warnings", "Any warnings associated with the change"},
    2547             :                     }
    2548             :                 },
    2549          14 :                 RPCExamples{
    2550          14 :                     HelpExampleCli("setwalletflag", "avoid_reuse")
    2551          14 :                   + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
    2552             :                 },
    2553          14 :             }.Check(request);
    2554             : 
    2555          10 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    2556          10 :     if (!wallet) return NullUniValue;
    2557          10 :     CWallet* const pwallet = wallet.get();
    2558             : 
    2559          10 :     std::string flag_str = request.params[0].get_str();
    2560          10 :     bool value = request.params[1].isNull() || request.params[1].get_bool();
    2561             : 
    2562          10 :     if (!WALLET_FLAG_MAP.count(flag_str)) {
    2563           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
    2564             :     }
    2565             : 
    2566          10 :     auto flag = WALLET_FLAG_MAP.at(flag_str);
    2567             : 
    2568          10 :     if (!(flag & MUTABLE_WALLET_FLAGS)) {
    2569           4 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
    2570             :     }
    2571             : 
    2572           6 :     UniValue res(UniValue::VOBJ);
    2573             : 
    2574           6 :     if (pwallet->IsWalletFlagSet(flag) == value) {
    2575           4 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
    2576             :     }
    2577             : 
    2578           2 :     res.pushKV("flag_name", flag_str);
    2579           2 :     res.pushKV("flag_state", value);
    2580             : 
    2581           2 :     if (value) {
    2582           2 :         pwallet->SetWalletFlag(flag);
    2583             :     } else {
    2584           0 :         pwallet->UnsetWalletFlag(flag);
    2585             :     }
    2586             : 
    2587           2 :     if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
    2588           2 :         res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
    2589           2 :     }
    2590             : 
    2591           2 :     return res;
    2592          38 : }
    2593             : 
    2594         368 : static UniValue createwallet(const JSONRPCRequest& request)
    2595             : {
    2596        3684 :     RPCHelpMan{
    2597         368 :         "createwallet",
    2598         368 :         "\nCreates and loads a new wallet.\n",
    2599        2948 :         {
    2600         368 :             {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
    2601         368 :             {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
    2602         368 :             {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
    2603         368 :             {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
    2604         368 :             {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
    2605         368 :             {"descriptors", RPCArg::Type::BOOL, /* default */ "false", "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"},
    2606         368 :             {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
    2607             :         },
    2608         368 :         RPCResult{
    2609         368 :             RPCResult::Type::OBJ, "", "",
    2610        1108 :             {
    2611         368 :                 {RPCResult::Type::STR, "name", "The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path."},
    2612         368 :                 {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
    2613             :             }
    2614             :         },
    2615         368 :         RPCExamples{
    2616         368 :             HelpExampleCli("createwallet", "\"testwallet\"")
    2617         368 :             + HelpExampleRpc("createwallet", "\"testwallet\"")
    2618             :         },
    2619         368 :     }.Check(request);
    2620             : 
    2621         364 :     WalletContext& context = EnsureWalletContext(request.context);
    2622             :     uint64_t flags = 0;
    2623         364 :     if (!request.params[1].isNull() && request.params[1].get_bool()) {
    2624             :         flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
    2625          31 :     }
    2626             : 
    2627         364 :     if (!request.params[2].isNull() && request.params[2].get_bool()) {
    2628          24 :         flags |= WALLET_FLAG_BLANK_WALLET;
    2629          24 :     }
    2630         364 :     SecureString passphrase;
    2631         364 :     passphrase.reserve(100);
    2632         364 :     std::vector<bilingual_str> warnings;
    2633         364 :     if (!request.params[3].isNull()) {
    2634         361 :         passphrase = request.params[3].get_str().c_str();
    2635         361 :         if (passphrase.empty()) {
    2636             :             // Empty string means unencrypted
    2637         354 :             warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
    2638         354 :         }
    2639             :     }
    2640             : 
    2641         364 :     if (!request.params[4].isNull() && request.params[4].get_bool()) {
    2642           2 :         flags |= WALLET_FLAG_AVOID_REUSE;
    2643           2 :     }
    2644         364 :     if (!request.params[5].isNull() && request.params[5].get_bool()) {
    2645          43 :         flags |= WALLET_FLAG_DESCRIPTORS;
    2646          43 :         warnings.emplace_back(Untranslated("Wallet is an experimental descriptor wallet"));
    2647          43 :     }
    2648             : 
    2649         364 :     DatabaseOptions options;
    2650         364 :     DatabaseStatus status;
    2651         364 :     options.require_create = true;
    2652         364 :     options.create_flags = flags;
    2653         364 :     options.create_passphrase = passphrase;
    2654         364 :     bilingual_str error;
    2655         364 :     Optional<bool> load_on_start = request.params[6].isNull() ? nullopt : Optional<bool>(request.params[6].get_bool());
    2656         364 :     std::shared_ptr<CWallet> wallet = CreateWallet(*context.chain, request.params[0].get_str(), load_on_start, options, status, error, warnings);
    2657         364 :     if (!wallet) {
    2658           4 :         RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
    2659           4 :         throw JSONRPCError(code, error.original);
    2660           4 :     }
    2661             : 
    2662         360 :     UniValue obj(UniValue::VOBJ);
    2663         360 :     obj.pushKV("name", wallet->GetName());
    2664         360 :     obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
    2665             : 
    2666             :     return obj;
    2667         412 : }
    2668             : 
    2669         131 : static UniValue unloadwallet(const JSONRPCRequest& request)
    2670             : {
    2671         532 :             RPCHelpMan{"unloadwallet",
    2672         131 :                 "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
    2673             :                 "Specifying the wallet name on a wallet endpoint is invalid.",
    2674         397 :                 {
    2675         131 :                     {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC request", "The name of the wallet to unload."},
    2676         131 :                     {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
    2677             :                 },
    2678         262 :                 RPCResult{RPCResult::Type::OBJ, "", "", {
    2679         131 :                     {RPCResult::Type::STR, "warning", "Warning message if wallet was not unloaded cleanly."},
    2680             :                 }},
    2681         131 :                 RPCExamples{
    2682         131 :                     HelpExampleCli("unloadwallet", "wallet_name")
    2683         131 :             + HelpExampleRpc("unloadwallet", "wallet_name")
    2684             :                 },
    2685         131 :             }.Check(request);
    2686             : 
    2687         127 :     std::string wallet_name;
    2688         127 :     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
    2689          35 :         if (!request.params[0].isNull()) {
    2690           2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot unload the requested wallet");
    2691             :         }
    2692             :     } else {
    2693          92 :         wallet_name = request.params[0].get_str();
    2694             :     }
    2695             : 
    2696         123 :     std::shared_ptr<CWallet> wallet = GetWallet(wallet_name);
    2697         123 :     if (!wallet) {
    2698           4 :         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
    2699             :     }
    2700             : 
    2701             :     // Release the "main" shared pointer and prevent further notifications.
    2702             :     // Note that any attempt to load the same wallet would fail until the wallet
    2703             :     // is destroyed (see CheckUniqueFileid).
    2704         119 :     std::vector<bilingual_str> warnings;
    2705         119 :     Optional<bool> load_on_start = request.params[1].isNull() ? nullopt : Optional<bool>(request.params[1].get_bool());
    2706         119 :     if (!RemoveWallet(wallet, load_on_start, warnings)) {
    2707           0 :         throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
    2708             :     }
    2709             : 
    2710         119 :     UnloadWallet(std::move(wallet));
    2711             : 
    2712         119 :     UniValue result(UniValue::VOBJ);
    2713         119 :     result.pushKV("warning", Join(warnings, Untranslated("\n")).original);
    2714             :     return result;
    2715         155 : }
    2716             : 
    2717         399 : static UniValue listunspent(const JSONRPCRequest& request)
    2718             : {
    2719        9177 :     RPCHelpMan{
    2720         399 :                 "listunspent",
    2721         399 :                 "\nReturns array of unspent transaction outputs\n"
    2722             :                 "with between minconf and maxconf (inclusive) confirmations.\n"
    2723             :                 "Optionally filter to only include txouts paid to specified addresses.\n",
    2724        2406 :                 {
    2725         399 :                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum confirmations to filter"},
    2726         399 :                     {"maxconf", RPCArg::Type::NUM, /* default */ "9999999", "The maximum confirmations to filter"},
    2727         798 :                     {"addresses", RPCArg::Type::ARR, /* default */ "empty array", "The bitcoin addresses to filter",
    2728         798 :                         {
    2729         399 :                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address"},
    2730             :                         },
    2731             :                     },
    2732         399 :                     {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true", "Include outputs that are not safe to spend\n"
    2733             :             "                  See description of \"safe\" attribute below."},
    2734         798 :                     {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options",
    2735        1999 :                         {
    2736         399 :                             {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
    2737         399 :                             {"maximumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
    2738         399 :                             {"maximumCount", RPCArg::Type::NUM, /* default */ "unlimited", "Maximum number of UTXOs"},
    2739         399 :                             {"minimumSumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
    2740             :                         },
    2741         399 :                         "query_options"},
    2742             :                 },
    2743         399 :                 RPCResult{
    2744         399 :                     RPCResult::Type::ARR, "", "",
    2745         798 :                     {
    2746         798 :                         {RPCResult::Type::OBJ, "", "",
    2747        5989 :                         {
    2748         399 :                             {RPCResult::Type::STR_HEX, "txid", "the transaction id"},
    2749         399 :                             {RPCResult::Type::NUM, "vout", "the vout value"},
    2750         399 :                             {RPCResult::Type::STR, "address", "the bitcoin address"},
    2751         399 :                             {RPCResult::Type::STR, "label", "The associated label, or \"\" for the default label"},
    2752         399 :                             {RPCResult::Type::STR, "scriptPubKey", "the script key"},
    2753         399 :                             {RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT},
    2754         399 :                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
    2755         399 :                             {RPCResult::Type::STR_HEX, "redeemScript", "The redeemScript if scriptPubKey is P2SH"},
    2756         399 :                             {RPCResult::Type::STR, "witnessScript", "witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH"},
    2757         399 :                             {RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
    2758         399 :                             {RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"},
    2759         399 :                             {RPCResult::Type::BOOL, "reused", "(only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)"},
    2760         399 :                             {RPCResult::Type::STR, "desc", "(only when solvable) A descriptor for spending this output"},
    2761         399 :                             {RPCResult::Type::BOOL, "safe", "Whether this output is considered safe to spend. Unconfirmed transactions\n"
    2762             :                                                             "from outside keys and unconfirmed replacement transactions are considered unsafe\n"
    2763             :                                                             "and are not eligible for spending by fundrawtransaction and sendtoaddress."},
    2764             :                         }},
    2765             :                     }
    2766             :                 },
    2767         399 :                 RPCExamples{
    2768         399 :                     HelpExampleCli("listunspent", "")
    2769         399 :             + HelpExampleCli("listunspent", "6 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
    2770         399 :             + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
    2771         399 :             + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
    2772         399 :             + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
    2773             :                 },
    2774         399 :             }.Check(request);
    2775             : 
    2776         395 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    2777         395 :     if (!wallet) return NullUniValue;
    2778         395 :     const CWallet* const pwallet = wallet.get();
    2779             : 
    2780             :     int nMinDepth = 1;
    2781         395 :     if (!request.params[0].isNull()) {
    2782          55 :         RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
    2783          55 :         nMinDepth = request.params[0].get_int();
    2784          55 :     }
    2785             : 
    2786             :     int nMaxDepth = 9999999;
    2787         395 :     if (!request.params[1].isNull()) {
    2788          10 :         RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
    2789          10 :         nMaxDepth = request.params[1].get_int();
    2790          10 :     }
    2791             : 
    2792         395 :     std::set<CTxDestination> destinations;
    2793         395 :     if (!request.params[2].isNull()) {
    2794           5 :         RPCTypeCheckArgument(request.params[2], UniValue::VARR);
    2795           5 :         UniValue inputs = request.params[2].get_array();
    2796          10 :         for (unsigned int idx = 0; idx < inputs.size(); idx++) {
    2797           5 :             const UniValue& input = inputs[idx];
    2798           5 :             CTxDestination dest = DecodeDestination(input.get_str());
    2799           5 :             if (!IsValidDestination(dest)) {
    2800           0 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str());
    2801             :             }
    2802           5 :             if (!destinations.insert(dest).second) {
    2803           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
    2804             :             }
    2805           5 :         }
    2806           5 :     }
    2807             : 
    2808             :     bool include_unsafe = true;
    2809         395 :     if (!request.params[3].isNull()) {
    2810           3 :         RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
    2811           3 :         include_unsafe = request.params[3].get_bool();
    2812           3 :     }
    2813             : 
    2814         395 :     CAmount nMinimumAmount = 0;
    2815         395 :     CAmount nMaximumAmount = MAX_MONEY;
    2816         395 :     CAmount nMinimumSumAmount = MAX_MONEY;
    2817             :     uint64_t nMaximumCount = 0;
    2818             : 
    2819         395 :     if (!request.params[4].isNull()) {
    2820          81 :         const UniValue& options = request.params[4].get_obj();
    2821             : 
    2822         324 :         RPCTypeCheckObj(options,
    2823         405 :             {
    2824          81 :                 {"minimumAmount", UniValueType()},
    2825          81 :                 {"maximumAmount", UniValueType()},
    2826          81 :                 {"minimumSumAmount", UniValueType()},
    2827          81 :                 {"maximumCount", UniValueType(UniValue::VNUM)},
    2828             :             },
    2829             :             true, true);
    2830             : 
    2831          81 :         if (options.exists("minimumAmount"))
    2832          81 :             nMinimumAmount = AmountFromValue(options["minimumAmount"]);
    2833             : 
    2834          81 :         if (options.exists("maximumAmount"))
    2835           0 :             nMaximumAmount = AmountFromValue(options["maximumAmount"]);
    2836             : 
    2837          81 :         if (options.exists("minimumSumAmount"))
    2838           0 :             nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
    2839             : 
    2840          81 :         if (options.exists("maximumCount"))
    2841           0 :             nMaximumCount = options["maximumCount"].get_int64();
    2842          81 :     }
    2843             : 
    2844             :     // Make sure the results are valid at least up to the most recent block
    2845             :     // the user could have gotten from another RPC command prior to now
    2846         395 :     pwallet->BlockUntilSyncedToCurrentChain();
    2847             : 
    2848         395 :     UniValue results(UniValue::VARR);
    2849         395 :     std::vector<COutput> vecOutputs;
    2850             :     {
    2851         395 :         CCoinControl cctl;
    2852         395 :         cctl.m_avoid_address_reuse = false;
    2853         395 :         cctl.m_min_depth = nMinDepth;
    2854         395 :         cctl.m_max_depth = nMaxDepth;
    2855         395 :         LOCK(pwallet->cs_wallet);
    2856         395 :         pwallet->AvailableCoins(vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount);
    2857         395 :     }
    2858             : 
    2859         395 :     LOCK(pwallet->cs_wallet);
    2860             : 
    2861         395 :     const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
    2862             : 
    2863       29911 :     for (const COutput& out : vecOutputs) {
    2864       29516 :         CTxDestination address;
    2865       29516 :         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
    2866       29516 :         bool fValidAddress = ExtractDestination(scriptPubKey, address);
    2867       29516 :         bool reused = avoid_reuse && pwallet->IsSpentKey(out.tx->GetHash(), out.i);
    2868             : 
    2869       29516 :         if (destinations.size() && (!fValidAddress || !destinations.count(address)))
    2870         363 :             continue;
    2871             : 
    2872       29153 :         UniValue entry(UniValue::VOBJ);
    2873       29153 :         entry.pushKV("txid", out.tx->GetHash().GetHex());
    2874       29153 :         entry.pushKV("vout", out.i);
    2875             : 
    2876       29153 :         if (fValidAddress) {
    2877       28966 :             entry.pushKV("address", EncodeDestination(address));
    2878             : 
    2879       28966 :             const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
    2880       28966 :             if (address_book_entry) {
    2881       28049 :                 entry.pushKV("label", address_book_entry->GetLabel());
    2882       28049 :             }
    2883             : 
    2884       28966 :             std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
    2885       28966 :             if (provider) {
    2886       28966 :                 if (scriptPubKey.IsPayToScriptHash()) {
    2887        1070 :                     const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address));
    2888        1070 :                     CScript redeemScript;
    2889        1070 :                     if (provider->GetCScript(hash, redeemScript)) {
    2890        1044 :                         entry.pushKV("redeemScript", HexStr(redeemScript));
    2891             :                         // Now check if the redeemScript is actually a P2WSH script
    2892        1044 :                         CTxDestination witness_destination;
    2893        1044 :                         if (redeemScript.IsPayToWitnessScriptHash()) {
    2894         339 :                             bool extracted = ExtractDestination(redeemScript, witness_destination);
    2895         339 :                             CHECK_NONFATAL(extracted);
    2896             :                             // Also return the witness script
    2897         339 :                             const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(witness_destination);
    2898         339 :                             CScriptID id;
    2899         339 :                             CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
    2900         339 :                             CScript witnessScript;
    2901         339 :                             if (provider->GetCScript(id, witnessScript)) {
    2902         339 :                                 entry.pushKV("witnessScript", HexStr(witnessScript));
    2903         339 :                             }
    2904         339 :                         }
    2905        1044 :                     }
    2906       28966 :                 } else if (scriptPubKey.IsPayToWitnessScriptHash()) {
    2907         485 :                     const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(address);
    2908         485 :                     CScriptID id;
    2909         485 :                     CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
    2910         485 :                     CScript witnessScript;
    2911         485 :                     if (provider->GetCScript(id, witnessScript)) {
    2912         484 :                         entry.pushKV("witnessScript", HexStr(witnessScript));
    2913         484 :                     }
    2914         485 :                 }
    2915             :             }
    2916       28966 :         }
    2917             : 
    2918       29153 :         entry.pushKV("scriptPubKey", HexStr(scriptPubKey));
    2919       29153 :         entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
    2920       29153 :         entry.pushKV("confirmations", out.nDepth);
    2921       29153 :         entry.pushKV("spendable", out.fSpendable);
    2922       29153 :         entry.pushKV("solvable", out.fSolvable);
    2923       29153 :         if (out.fSolvable) {
    2924       29025 :             std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
    2925       29025 :             if (provider) {
    2926       29025 :                 auto descriptor = InferDescriptor(scriptPubKey, *provider);
    2927       29025 :                 entry.pushKV("desc", descriptor->ToString());
    2928       29025 :             }
    2929       29025 :         }
    2930       29153 :         if (avoid_reuse) entry.pushKV("reused", reused);
    2931       29153 :         entry.pushKV("safe", out.fSafe);
    2932       29153 :         results.push_back(entry);
    2933       29516 :     }
    2934             : 
    2935         395 :     return results;
    2936         475 : }
    2937             : 
    2938         164 : void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options, CCoinControl& coinControl)
    2939             : {
    2940             :     // Make sure the results are valid at least up to the most recent block
    2941             :     // the user could have gotten from another RPC command prior to now
    2942         164 :     pwallet->BlockUntilSyncedToCurrentChain();
    2943             : 
    2944         164 :     change_position = -1;
    2945             :     bool lockUnspents = false;
    2946         164 :     UniValue subtractFeeFromOutputs;
    2947         164 :     std::set<int> setSubtractFeeFromOutputs;
    2948             : 
    2949         164 :     if (!options.isNull()) {
    2950         107 :       if (options.type() == UniValue::VBOOL) {
    2951             :         // backward compatibility bool only fallback
    2952           1 :         coinControl.fAllowWatchOnly = options.get_bool();
    2953           1 :       }
    2954             :       else {
    2955         106 :         RPCTypeCheckArgument(options, UniValue::VOBJ);
    2956        2120 :         RPCTypeCheckObj(options,
    2957        2228 :             {
    2958         106 :                 {"add_inputs", UniValueType(UniValue::VBOOL)},
    2959         106 :                 {"add_to_wallet", UniValueType(UniValue::VBOOL)},
    2960         106 :                 {"changeAddress", UniValueType(UniValue::VSTR)},
    2961         106 :                 {"change_address", UniValueType(UniValue::VSTR)},
    2962         106 :                 {"changePosition", UniValueType(UniValue::VNUM)},
    2963         106 :                 {"change_position", UniValueType(UniValue::VNUM)},
    2964         106 :                 {"change_type", UniValueType(UniValue::VSTR)},
    2965         106 :                 {"includeWatching", UniValueType(UniValue::VBOOL)},
    2966         106 :                 {"include_watching", UniValueType(UniValue::VBOOL)},
    2967         106 :                 {"inputs", UniValueType(UniValue::VARR)},
    2968         106 :                 {"lockUnspents", UniValueType(UniValue::VBOOL)},
    2969         106 :                 {"lock_unspents", UniValueType(UniValue::VBOOL)},
    2970         106 :                 {"locktime", UniValueType(UniValue::VNUM)},
    2971         106 :                 {"feeRate", UniValueType()}, // will be checked below,
    2972         106 :                 {"psbt", UniValueType(UniValue::VBOOL)},
    2973         106 :                 {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
    2974         106 :                 {"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
    2975         106 :                 {"replaceable", UniValueType(UniValue::VBOOL)},
    2976         106 :                 {"conf_target", UniValueType(UniValue::VNUM)},
    2977         106 :                 {"estimate_mode", UniValueType(UniValue::VSTR)},
    2978             :             },
    2979             :             true, true);
    2980             : 
    2981         104 :         if (options.exists("add_inputs") ) {
    2982          23 :             coinControl.m_add_inputs = options["add_inputs"].get_bool();
    2983          23 :         }
    2984             : 
    2985         104 :         if (options.exists("changeAddress") || options.exists("change_address")) {
    2986          21 :             const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str();
    2987          21 :             CTxDestination dest = DecodeDestination(change_address_str);
    2988             : 
    2989          21 :             if (!IsValidDestination(dest)) {
    2990           2 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");
    2991             :             }
    2992             : 
    2993          19 :             coinControl.destChange = dest;
    2994          21 :         }
    2995             : 
    2996         102 :         if (options.exists("changePosition") || options.exists("change_position")) {
    2997           7 :             change_position = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).get_int();
    2998           7 :         }
    2999             : 
    3000         102 :         if (options.exists("change_type")) {
    3001           4 :             if (options.exists("changeAddress") || options.exists("change_address")) {
    3002           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");
    3003             :             }
    3004           4 :             OutputType out_type;
    3005           4 :             if (!ParseOutputType(options["change_type"].get_str(), out_type)) {
    3006           1 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
    3007             :             }
    3008           2 :             coinControl.m_change_type.emplace(out_type);
    3009           4 :         }
    3010             : 
    3011         100 :         const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"];
    3012         100 :         coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, *pwallet);
    3013             : 
    3014         100 :         if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
    3015           7 :             lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
    3016           7 :         }
    3017             : 
    3018         100 :         if (options.exists("feeRate"))
    3019             :         {
    3020          27 :             if (options.exists("conf_target")) {
    3021           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate");
    3022             :             }
    3023          27 :             if (options.exists("estimate_mode")) {
    3024           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
    3025             :             }
    3026          27 :             coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
    3027          27 :             coinControl.fOverrideFeeRate = true;
    3028          27 :         }
    3029             : 
    3030         100 :         if (options.exists("subtractFeeFromOutputs") || options.exists("subtract_fee_from_outputs") )
    3031          17 :             subtractFeeFromOutputs = (options.exists("subtract_fee_from_outputs") ? options["subtract_fee_from_outputs"] : options["subtractFeeFromOutputs"]).get_array();
    3032             : 
    3033         100 :         if (options.exists("replaceable")) {
    3034           8 :             coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
    3035           8 :         }
    3036         100 :         SetFeeEstimateMode(pwallet, coinControl, options["estimate_mode"], options["conf_target"]);
    3037         100 :       }
    3038             :     } else {
    3039             :         // if options is null and not a bool
    3040          57 :         coinControl.fAllowWatchOnly = ParseIncludeWatchonly(NullUniValue, *pwallet);
    3041             :     }
    3042             : 
    3043         157 :     if (tx.vout.size() == 0)
    3044           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
    3045             : 
    3046         157 :     if (change_position != -1 && (change_position < 0 || (unsigned int)change_position > tx.vout.size()))
    3047           1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
    3048             : 
    3049         174 :     for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
    3050          18 :         int pos = subtractFeeFromOutputs[idx].get_int();
    3051          18 :         if (setSubtractFeeFromOutputs.count(pos))
    3052           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
    3053          18 :         if (pos < 0)
    3054           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
    3055          18 :         if (pos >= int(tx.vout.size()))
    3056           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
    3057          18 :         setSubtractFeeFromOutputs.insert(pos);
    3058          18 :     }
    3059             : 
    3060         156 :     bilingual_str error;
    3061             : 
    3062         156 :     if (!pwallet->FundTransaction(tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
    3063          28 :         throw JSONRPCError(RPC_WALLET_ERROR, error.original);
    3064             :     }
    3065         173 : }
    3066             : 
    3067          82 : static UniValue fundrawtransaction(const JSONRPCRequest& request)
    3068             : {
    3069        1413 :     RPCHelpMan{"fundrawtransaction",
    3070          82 :                 "\nIf the transaction has no inputs, they will be automatically selected to meet its out value.\n"
    3071             :                 "It will add at most one change output to the outputs.\n"
    3072             :                 "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
    3073             :                 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
    3074             :                 "The inputs added will not be signed, use signrawtransactionwithkey\n"
    3075             :                 " or signrawtransactionwithwallet for that.\n"
    3076             :                 "Note that all existing inputs must have their previous output transaction be in the wallet.\n"
    3077             :                 "Note that all inputs selected must be of standard form and P2SH scripts must be\n"
    3078             :                 "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
    3079             :                 "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
    3080             :                 "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
    3081         348 :                 {
    3082          82 :                     {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
    3083         164 :                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
    3084         996 :                         {
    3085          82 :                             {"add_inputs", RPCArg::Type::BOOL, /* default */ "true", "For a transaction with existing inputs, automatically include more if they are not enough."},
    3086          82 :                             {"changeAddress", RPCArg::Type::STR, /* default */ "pool address", "The bitcoin address to receive the change"},
    3087          82 :                             {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
    3088          82 :                             {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
    3089          82 :                             {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n"
    3090             :                                                           "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
    3091             :                                                           "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
    3092          82 :                             {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
    3093          82 :                             {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
    3094         164 :                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The integers.\n"
    3095             :                             "                              The fee will be equally deducted from the amount of each specified output.\n"
    3096             :                             "                              Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
    3097             :                             "                              If no outputs are specified here, the sender pays the fee.",
    3098         164 :                                 {
    3099          82 :                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
    3100             :                                 },
    3101             :                             },
    3102          82 :                             {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
    3103             :                             "                              Allows this transaction to be replaced by a transaction with higher fees"},
    3104          82 :                             {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
    3105         164 :                             {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
    3106          82 :                             "       \"" + FeeModes("\"\n\"") + "\""},
    3107             :                         },
    3108          82 :                         "options"},
    3109          82 :                     {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
    3110             :                         "If iswitness is not present, heuristic tests will be used in decoding.\n"
    3111             :                         "If true, only witness deserialization will be tried.\n"
    3112             :                         "If false, only non-witness deserialization will be tried.\n"
    3113             :                         "This boolean should reflect whether the transaction has inputs\n"
    3114             :                         "(e.g. fully valid, or on-chain transactions), if known by the caller."
    3115             :                     },
    3116             :                 },
    3117          82 :                 RPCResult{
    3118          82 :                     RPCResult::Type::OBJ, "", "",
    3119         332 :                     {
    3120          82 :                         {RPCResult::Type::STR_HEX, "hex", "The resulting raw transaction (hex-encoded string)"},
    3121          82 :                         {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
    3122          82 :                         {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
    3123             :                     }
    3124             :                                 },
    3125          82 :                                 RPCExamples{
    3126          82 :                             "\nCreate a transaction with no inputs\n"
    3127          82 :                             + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
    3128             :                             "\nAdd sufficient unsigned inputs to meet the output value\n"
    3129          82 :                             + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
    3130             :                             "\nSign the transaction\n"
    3131          82 :                             + HelpExampleCli("signrawtransactionwithwallet", "\"fundedtransactionhex\"") +
    3132             :                             "\nSend the transaction\n"
    3133          82 :                             + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
    3134             :                                 },
    3135          82 :     }.Check(request);
    3136             : 
    3137          78 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3138          78 :     if (!wallet) return NullUniValue;
    3139          78 :     CWallet* const pwallet = wallet.get();
    3140             : 
    3141          78 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
    3142             : 
    3143             :     // parse hex string from parameter
    3144          78 :     CMutableTransaction tx;
    3145          78 :     bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
    3146          78 :     bool try_no_witness = request.params[2].isNull() ? true : !request.params[2].get_bool();
    3147          78 :     if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
    3148           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
    3149             :     }
    3150             : 
    3151          78 :     CAmount fee;
    3152          78 :     int change_position;
    3153          78 :     CCoinControl coin_control;
    3154             :     // Automatically select (additional) coins. Can be overridden by options.add_inputs.
    3155          78 :     coin_control.m_add_inputs = true;
    3156          78 :     FundTransaction(pwallet, tx, fee, change_position, request.params[1], coin_control);
    3157             : 
    3158          59 :     UniValue result(UniValue::VOBJ);
    3159          59 :     result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
    3160          59 :     result.pushKV("fee", ValueFromAmount(fee));
    3161          59 :     result.pushKV("changepos", change_position);
    3162             : 
    3163          59 :     return result;
    3164         170 : }
    3165             : 
    3166        1653 : UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
    3167             : {
    3168       26460 :             RPCHelpMan{"signrawtransactionwithwallet",
    3169             :                 "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
    3170             :                 "The second optional argument (may be null) is an array of previous transaction outputs that\n"
    3171        1653 :                 "this transaction depends on but may not yet be in the block chain." +
    3172             :         HELP_REQUIRING_PASSPHRASE,
    3173        6632 :                 {
    3174        1653 :                     {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
    3175        3306 :                     {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The previous dependent transaction outputs",
    3176        3306 :                         {
    3177        3306 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    3178       11575 :                                 {
    3179        1653 :                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    3180        1653 :                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    3181        1653 :                                     {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
    3182        1653 :                                     {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
    3183        1653 :                                     {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
    3184        1653 :                                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"},
    3185             :                                 },
    3186             :                             },
    3187             :                         },
    3188             :                     },
    3189        1653 :                     {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of\n"
    3190             :             "       \"ALL\"\n"
    3191             :             "       \"NONE\"\n"
    3192             :             "       \"SINGLE\"\n"
    3193             :             "       \"ALL|ANYONECANPAY\"\n"
    3194             :             "       \"NONE|ANYONECANPAY\"\n"
    3195             :             "       \"SINGLE|ANYONECANPAY\""},
    3196             :                 },
    3197        1653 :                 RPCResult{
    3198        1653 :                     RPCResult::Type::OBJ, "", "",
    3199        6616 :                     {
    3200        1653 :                         {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"},
    3201        1653 :                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    3202        3306 :                         {RPCResult::Type::ARR, "errors", /* optional */ true, "Script verification errors (if there are any)",
    3203        3306 :                         {
    3204        3306 :                             {RPCResult::Type::OBJ, "", "",
    3205        9922 :                             {
    3206        1653 :                                 {RPCResult::Type::STR_HEX, "txid", "The hash of the referenced, previous transaction"},
    3207        1653 :                                 {RPCResult::Type::NUM, "vout", "The index of the output to spent and used as input"},
    3208        1653 :                                 {RPCResult::Type::STR_HEX, "scriptSig", "The hex-encoded signature script"},
    3209        1653 :                                 {RPCResult::Type::NUM, "sequence", "Script sequence number"},
    3210        1653 :                                 {RPCResult::Type::STR, "error", "Verification or signing error related to the input"},
    3211             :                             }},
    3212             :                         }},
    3213             :                     }
    3214             :                 },
    3215        1653 :                 RPCExamples{
    3216        1653 :                     HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
    3217        1653 :             + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
    3218             :                 },
    3219        1653 :             }.Check(request);
    3220             : 
    3221        1649 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3222        1649 :     if (!wallet) return NullUniValue;
    3223        1649 :     const CWallet* const pwallet = wallet.get();
    3224             : 
    3225        1649 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
    3226             : 
    3227        1649 :     CMutableTransaction mtx;
    3228        1649 :     if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) {
    3229           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
    3230             :     }
    3231             : 
    3232             :     // Sign the transaction
    3233        1649 :     LOCK(pwallet->cs_wallet);
    3234        1649 :     EnsureWalletIsUnlocked(pwallet);
    3235             : 
    3236             :     // Fetch previous transactions (inputs):
    3237        1648 :     std::map<COutPoint, Coin> coins;
    3238       10218 :     for (const CTxIn& txin : mtx.vin) {
    3239        8570 :         coins[txin.prevout]; // Create empty map entry keyed by prevout.
    3240             :     }
    3241        1648 :     pwallet->chain().findCoins(coins);
    3242             : 
    3243             :     // Parse the prevtxs array
    3244        1648 :     ParsePrevouts(request.params[1], nullptr, coins);
    3245             : 
    3246        1639 :     int nHashType = ParseSighashString(request.params[2]);
    3247             : 
    3248             :     // Script verification errors
    3249        1639 :     std::map<int, std::string> input_errors;
    3250             : 
    3251        1639 :     bool complete = pwallet->SignTransaction(mtx, coins, nHashType, input_errors);
    3252        1639 :     UniValue result(UniValue::VOBJ);
    3253        1639 :     SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
    3254        1637 :     return result;
    3255        1741 : }
    3256             : 
    3257         117 : static UniValue bumpfee(const JSONRPCRequest& request)
    3258             : {
    3259         117 :     bool want_psbt = request.strMethod == "psbtbumpfee";
    3260             : 
    3261        1053 :     RPCHelpMan{request.strMethod,
    3262         117 :         "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
    3263         117 :         + std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") +
    3264             :         "An opt-in RBF transaction with the given txid must be in the wallet.\n"
    3265             :         "The command will pay the additional fee by reducing change outputs or adding inputs when necessary. It may add a new change output if one does not already exist.\n"
    3266             :         "All inputs in the original transaction will be included in the replacement transaction.\n"
    3267             :         "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
    3268             :         "By default, the new fee will be calculated automatically using estimatesmartfee.\n"
    3269             :         "The user can specify a confirmation target for estimatesmartfee.\n"
    3270         117 :         "Alternatively, the user can specify a fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction.\n"
    3271             :         "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
    3272             :         "returned by getnetworkinfo) to enter the node's mempool.\n",
    3273         359 :         {
    3274         117 :             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
    3275         234 :             {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
    3276         593 :                 {
    3277         117 :                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
    3278         234 :                     {"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'conf_target'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n"
    3279             :     "                         Specify a fee rate instead of relying on the built-in fee estimator.\n"
    3280         117 :                              "Must be at least 0.0001 " + CURRENCY_UNIT + " per kB higher than the current transaction fee rate.\n"},
    3281         117 :                     {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n"
    3282             :     "                         marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
    3283             :     "                         be left unchanged from the original. If false, any input sequence numbers in the\n"
    3284             :     "                         original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
    3285             :     "                         so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
    3286             :     "                         still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
    3287             :     "                         are replaceable)."},
    3288         234 :                     {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
    3289         117 :     "         \"" + FeeModes("\"\n\"") + "\""},
    3290             :                 },
    3291         117 :                 "options"},
    3292             :         },
    3293         117 :         RPCResult{
    3294         351 :             RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
    3295         234 :             {
    3296         117 :                 {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction." + std::string(want_psbt ? "" : " Only returned when wallet private keys are disabled. (DEPRECATED)")},
    3297             :             },
    3298         117 :             want_psbt ? std::vector<RPCResult>{} : std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."}}
    3299             :             ),
    3300         476 :             {
    3301         117 :                 {RPCResult::Type::STR_AMOUNT, "origfee", "The fee of the replaced transaction."},
    3302         117 :                 {RPCResult::Type::STR_AMOUNT, "fee", "The fee of the new transaction."},
    3303         234 :                 {RPCResult::Type::ARR, "errors", "Errors encountered during processing (may be empty).",
    3304         234 :                 {
    3305         117 :                     {RPCResult::Type::STR, "", ""},
    3306             :                 }},
    3307             :             })
    3308             :         },
    3309         117 :         RPCExamples{
    3310         234 :     "\nBump the fee, get the new transaction\'s" + std::string(want_psbt ? "psbt" : "txid") + "\n" +
    3311         117 :             HelpExampleCli(request.strMethod, "<txid>")
    3312             :         },
    3313         117 :     }.Check(request);
    3314             : 
    3315         109 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3316         109 :     if (!wallet) return NullUniValue;
    3317         109 :     CWallet* const pwallet = wallet.get();
    3318             : 
    3319         109 :     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
    3320           2 :         if (!pwallet->chain().rpcEnableDeprecated("bumpfee")) {
    3321           1 :             throw JSONRPCError(RPC_METHOD_DEPRECATED, "Using bumpfee with wallets that have private keys disabled is deprecated. Use psbtbumpfee instead or restart bitcoind with -deprecatedrpc=bumpfee. This functionality will be removed in 0.22");
    3322             :         }
    3323             :         want_psbt = true;
    3324           1 :     }
    3325             : 
    3326         108 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
    3327         108 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    3328             : 
    3329         108 :     CCoinControl coin_control;
    3330         108 :     coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
    3331             :     // optional parameters
    3332         108 :     coin_control.m_signal_bip125_rbf = true;
    3333             : 
    3334         108 :     if (!request.params[1].isNull()) {
    3335          21 :         UniValue options = request.params[1];
    3336         105 :         RPCTypeCheckObj(options,
    3337         129 :             {
    3338          21 :                 {"confTarget", UniValueType(UniValue::VNUM)},
    3339          21 :                 {"conf_target", UniValueType(UniValue::VNUM)},
    3340          21 :                 {"fee_rate", UniValueType(UniValue::VNUM)},
    3341          21 :                 {"replaceable", UniValueType(UniValue::VBOOL)},
    3342          21 :                 {"estimate_mode", UniValueType(UniValue::VSTR)},
    3343             :             },
    3344             :             true, true);
    3345             : 
    3346          18 :         if (options.exists("confTarget") && options.exists("conf_target")) {
    3347           1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and conf_target options should not both be set. Use conf_target (confTarget is deprecated).");
    3348             :         }
    3349             : 
    3350          17 :         auto conf_target = options.exists("confTarget") ? options["confTarget"] : options["conf_target"];
    3351             : 
    3352          17 :         if (!conf_target.isNull()) {
    3353           2 :             if (options.exists("fee_rate")) {
    3354           2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "conf_target can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
    3355             :             }
    3356           0 :             coin_control.m_confirm_target = ParseConfirmTarget(conf_target, pwallet->chain().estimateMaxBlocks());
    3357          15 :         } else if (options.exists("fee_rate")) {
    3358          13 :             CFeeRate fee_rate(AmountFromValue(options["fee_rate"]));
    3359          12 :             if (fee_rate <= CFeeRate(0)) {
    3360           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid fee_rate %s (must be greater than 0)", fee_rate.ToString()));
    3361             :             }
    3362          12 :             coin_control.m_feerate = fee_rate;
    3363          13 :         }
    3364             : 
    3365          14 :         if (options.exists("replaceable")) {
    3366           1 :             coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
    3367           1 :         }
    3368          14 :         SetFeeEstimateMode(pwallet, coin_control, options["estimate_mode"], conf_target);
    3369          21 :     }
    3370             : 
    3371             :     // Make sure the results are valid at least up to the most recent block
    3372             :     // the user could have gotten from another RPC command prior to now
    3373          99 :     pwallet->BlockUntilSyncedToCurrentChain();
    3374             : 
    3375          99 :     LOCK(pwallet->cs_wallet);
    3376          99 :     EnsureWalletIsUnlocked(pwallet);
    3377             : 
    3378             : 
    3379          98 :     std::vector<bilingual_str> errors;
    3380          98 :     CAmount old_fee;
    3381          98 :     CAmount new_fee;
    3382          98 :     CMutableTransaction mtx;
    3383             :     feebumper::Result res;
    3384             :     // Targeting feerate bump.
    3385          98 :     res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
    3386          98 :     if (res != feebumper::Result::OK) {
    3387           9 :         switch(res) {
    3388             :             case feebumper::Result::INVALID_ADDRESS_OR_KEY:
    3389           0 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0].original);
    3390             :                 break;
    3391             :             case feebumper::Result::INVALID_REQUEST:
    3392           0 :                 throw JSONRPCError(RPC_INVALID_REQUEST, errors[0].original);
    3393             :                 break;
    3394             :             case feebumper::Result::INVALID_PARAMETER:
    3395           2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0].original);
    3396             :                 break;
    3397             :             case feebumper::Result::WALLET_ERROR:
    3398           7 :                 throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
    3399             :                 break;
    3400             :             default:
    3401           0 :                 throw JSONRPCError(RPC_MISC_ERROR, errors[0].original);
    3402             :                 break;
    3403             :         }
    3404             :     }
    3405             : 
    3406          89 :     UniValue result(UniValue::VOBJ);
    3407             : 
    3408             :     // If wallet private keys are enabled, return the new transaction id,
    3409             :     // otherwise return the base64-encoded unsigned PSBT of the new transaction.
    3410          89 :     if (!want_psbt) {
    3411          85 :         if (!feebumper::SignTransaction(*pwallet, mtx)) {
    3412           0 :             throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
    3413             :         }
    3414             : 
    3415          85 :         uint256 txid;
    3416          85 :         if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
    3417           0 :             throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
    3418             :         }
    3419             : 
    3420          85 :         result.pushKV("txid", txid.GetHex());
    3421          85 :     } else {
    3422           4 :         PartiallySignedTransaction psbtx(mtx);
    3423           4 :         bool complete = false;
    3424           4 :         const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */);
    3425           4 :         CHECK_NONFATAL(err == TransactionError::OK);
    3426           4 :         CHECK_NONFATAL(!complete);
    3427           4 :         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    3428           4 :         ssTx << psbtx;
    3429           4 :         result.pushKV("psbt", EncodeBase64(ssTx.str()));
    3430           4 :     }
    3431             : 
    3432          89 :     result.pushKV("origfee", ValueFromAmount(old_fee));
    3433          89 :     result.pushKV("fee", ValueFromAmount(new_fee));
    3434          89 :     UniValue result_errors(UniValue::VARR);
    3435          89 :     for (const bilingual_str& error : errors) {
    3436           0 :         result_errors.push_back(error.original);
    3437             :     }
    3438          89 :     result.pushKV("errors", result_errors);
    3439             : 
    3440          89 :     return result;
    3441         273 : }
    3442             : 
    3443           7 : static UniValue psbtbumpfee(const JSONRPCRequest& request)
    3444             : {
    3445           7 :     return bumpfee(request);
    3446             : }
    3447             : 
    3448          11 : UniValue rescanblockchain(const JSONRPCRequest& request)
    3449             : {
    3450          55 :             RPCHelpMan{"rescanblockchain",
    3451          11 :                 "\nRescan the local blockchain for wallet related transactions.\n"
    3452             :                 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
    3453          37 :                 {
    3454          11 :                     {"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"},
    3455          11 :                     {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
    3456             :                 },
    3457          11 :                 RPCResult{
    3458          11 :                     RPCResult::Type::OBJ, "", "",
    3459          37 :                     {
    3460          11 :                         {RPCResult::Type::NUM, "start_height", "The block height where the rescan started (the requested height or 0)"},
    3461          11 :                         {RPCResult::Type::NUM, "stop_height", "The height of the last rescanned block. May be null in rare cases if there was a reorg and the call didn't scan any blocks because they were already scanned in the background."},
    3462             :                     }
    3463             :                 },
    3464          11 :                 RPCExamples{
    3465          11 :                     HelpExampleCli("rescanblockchain", "100000 120000")
    3466          11 :             + HelpExampleRpc("rescanblockchain", "100000, 120000")
    3467             :                 },
    3468          11 :             }.Check(request);
    3469             : 
    3470           7 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3471           7 :     if (!wallet) return NullUniValue;
    3472           7 :     CWallet* const pwallet = wallet.get();
    3473             : 
    3474           7 :     WalletRescanReserver reserver(*pwallet);
    3475           7 :     if (!reserver.reserve()) {
    3476           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
    3477             :     }
    3478             : 
    3479             :     int start_height = 0;
    3480           7 :     Optional<int> stop_height;
    3481           7 :     uint256 start_block;
    3482             :     {
    3483           7 :         LOCK(pwallet->cs_wallet);
    3484           7 :         int tip_height = pwallet->GetLastBlockHeight();
    3485             : 
    3486           7 :         if (!request.params[0].isNull()) {
    3487           2 :             start_height = request.params[0].get_int();
    3488           2 :             if (start_height < 0 || start_height > tip_height) {
    3489           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
    3490             :             }
    3491             :         }
    3492             : 
    3493           7 :         if (!request.params[1].isNull()) {
    3494           2 :             stop_height = request.params[1].get_int();
    3495           2 :             if (*stop_height < 0 || *stop_height > tip_height) {
    3496           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
    3497           2 :             } else if (*stop_height < start_height) {
    3498           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
    3499             :             }
    3500             :         }
    3501             : 
    3502             :         // We can't rescan beyond non-pruned blocks, stop and throw an error
    3503           7 :         if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(), start_height, stop_height)) {
    3504           0 :             throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
    3505             :         }
    3506             : 
    3507           7 :         CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), start_height, FoundBlock().hash(start_block)));
    3508           7 :     }
    3509             : 
    3510           7 :     CWallet::ScanResult result =
    3511           7 :         pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, true /* fUpdate */);
    3512           7 :     switch (result.status) {
    3513             :     case CWallet::ScanResult::SUCCESS:
    3514             :         break;
    3515             :     case CWallet::ScanResult::FAILURE:
    3516           0 :         throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
    3517             :     case CWallet::ScanResult::USER_ABORT:
    3518           0 :         throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
    3519             :         // no default case, so the compiler can warn about missing cases
    3520             :     }
    3521           7 :     UniValue response(UniValue::VOBJ);
    3522           7 :     response.pushKV("start_height", start_height);
    3523           7 :     response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue());
    3524           7 :     return response;
    3525          35 : }
    3526             : 
    3527             : class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
    3528             : {
    3529             : public:
    3530             :     const SigningProvider * const provider;
    3531             : 
    3532         291 :     void ProcessSubScript(const CScript& subscript, UniValue& obj) const
    3533             :     {
    3534             :         // Always present: script type and redeemscript
    3535         291 :         std::vector<std::vector<unsigned char>> solutions_data;
    3536         291 :         TxoutType which_type = Solver(subscript, solutions_data);
    3537         291 :         obj.pushKV("script", GetTxnOutputType(which_type));
    3538         291 :         obj.pushKV("hex", HexStr(subscript));
    3539             : 
    3540         291 :         CTxDestination embedded;
    3541         291 :         if (ExtractDestination(subscript, embedded)) {
    3542             :             // Only when the script corresponds to an address.
    3543         161 :             UniValue subobj(UniValue::VOBJ);
    3544         161 :             UniValue detail = DescribeAddress(embedded);
    3545         161 :             subobj.pushKVs(detail);
    3546         161 :             UniValue wallet_detail = boost::apply_visitor(*this, embedded);
    3547         161 :             subobj.pushKVs(wallet_detail);
    3548         161 :             subobj.pushKV("address", EncodeDestination(embedded));
    3549         161 :             subobj.pushKV("scriptPubKey", HexStr(subscript));
    3550             :             // Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
    3551         161 :             if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
    3552         161 :             obj.pushKV("embedded", std::move(subobj));
    3553         291 :         } else if (which_type == TxoutType::MULTISIG) {
    3554             :             // Also report some information on multisig scripts (which do not have a corresponding address).
    3555             :             // TODO: abstract out the common functionality between this logic and ExtractDestinations.
    3556         130 :             obj.pushKV("sigsrequired", solutions_data[0][0]);
    3557         130 :             UniValue pubkeys(UniValue::VARR);
    3558         450 :             for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
    3559         320 :                 CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
    3560         320 :                 pubkeys.push_back(HexStr(key));
    3561         320 :             }
    3562         130 :             obj.pushKV("pubkeys", std::move(pubkeys));
    3563         130 :         }
    3564         291 :     }
    3565             : 
    3566        1898 :     explicit DescribeWalletAddressVisitor(const SigningProvider* _provider) : provider(_provider) {}
    3567             : 
    3568           0 :     UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); }
    3569             : 
    3570         194 :     UniValue operator()(const PKHash& pkhash) const
    3571             :     {
    3572         194 :         CKeyID keyID{ToKeyID(pkhash)};
    3573         194 :         UniValue obj(UniValue::VOBJ);
    3574         194 :         CPubKey vchPubKey;
    3575         194 :         if (provider && provider->GetPubKey(keyID, vchPubKey)) {
    3576         175 :             obj.pushKV("pubkey", HexStr(vchPubKey));
    3577         175 :             obj.pushKV("iscompressed", vchPubKey.IsCompressed());
    3578         175 :         }
    3579             :         return obj;
    3580         194 :     }
    3581             : 
    3582         220 :     UniValue operator()(const ScriptHash& scripthash) const
    3583             :     {
    3584         220 :         CScriptID scriptID(scripthash);
    3585         220 :         UniValue obj(UniValue::VOBJ);
    3586         220 :         CScript subscript;
    3587         220 :         if (provider && provider->GetCScript(scriptID, subscript)) {
    3588         213 :             ProcessSubScript(subscript, obj);
    3589             :         }
    3590             :         return obj;
    3591         220 :     }
    3592             : 
    3593         598 :     UniValue operator()(const WitnessV0KeyHash& id) const
    3594             :     {
    3595         598 :         UniValue obj(UniValue::VOBJ);
    3596         598 :         CPubKey pubkey;
    3597         598 :         if (provider && provider->GetPubKey(ToKeyID(id), pubkey)) {
    3598         549 :             obj.pushKV("pubkey", HexStr(pubkey));
    3599         549 :         }
    3600             :         return obj;
    3601         598 :     }
    3602             : 
    3603          98 :     UniValue operator()(const WitnessV0ScriptHash& id) const
    3604             :     {
    3605          98 :         UniValue obj(UniValue::VOBJ);
    3606          98 :         CScript subscript;
    3607          98 :         CRIPEMD160 hasher;
    3608          98 :         uint160 hash;
    3609          98 :         hasher.Write(id.begin(), 32).Finalize(hash.begin());
    3610          98 :         if (provider && provider->GetCScript(CScriptID(hash), subscript)) {
    3611          78 :             ProcessSubScript(subscript, obj);
    3612             :         }
    3613             :         return obj;
    3614          98 :     }
    3615             : 
    3616           0 :     UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); }
    3617             : };
    3618             : 
    3619         949 : static UniValue DescribeWalletAddress(const CWallet* const pwallet, const CTxDestination& dest)
    3620             : {
    3621         949 :     UniValue ret(UniValue::VOBJ);
    3622         949 :     UniValue detail = DescribeAddress(dest);
    3623         949 :     CScript script = GetScriptForDestination(dest);
    3624         949 :     std::unique_ptr<SigningProvider> provider = nullptr;
    3625         949 :     if (pwallet) {
    3626         949 :         provider = pwallet->GetSolvingProvider(script);
    3627         949 :     }
    3628         949 :     ret.pushKVs(detail);
    3629         949 :     ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(provider.get()), dest));
    3630             :     return ret;
    3631         949 : }
    3632             : 
    3633             : /** Convert CAddressBookData to JSON record.  */
    3634         144 : static UniValue AddressBookDataToJSON(const CAddressBookData& data, const bool verbose)
    3635             : {
    3636         144 :     UniValue ret(UniValue::VOBJ);
    3637         144 :     if (verbose) {
    3638           0 :         ret.pushKV("name", data.GetLabel());
    3639           0 :     }
    3640         144 :     ret.pushKV("purpose", data.purpose);
    3641             :     return ret;
    3642         144 : }
    3643             : 
    3644         955 : UniValue getaddressinfo(const JSONRPCRequest& request)
    3645             : {
    3646       23877 :             RPCHelpMan{"getaddressinfo",
    3647         955 :                 "\nReturn information about the given bitcoin address.\n"
    3648             :                 "Some of the information will only be present if the address is in the active wallet.\n",
    3649        1910 :                 {
    3650         955 :                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for which to get information."},
    3651             :                 },
    3652         955 :                 RPCResult{
    3653         955 :                     RPCResult::Type::OBJ, "", "",
    3654       22940 :                     {
    3655         955 :                         {RPCResult::Type::STR, "address", "The bitcoin address validated."},
    3656         955 :                         {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address."},
    3657         955 :                         {RPCResult::Type::BOOL, "ismine", "If the address is yours."},
    3658         955 :                         {RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."},
    3659         955 :                         {RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."},
    3660         955 :                         {RPCResult::Type::STR, "desc", /* optional */ true, "A descriptor for spending coins sent to this address (only when solvable)."},
    3661         955 :                         {RPCResult::Type::BOOL, "isscript", "If the key is a script."},
    3662         955 :                         {RPCResult::Type::BOOL, "ischange", "If the address was used for change output."},
    3663         955 :                         {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address."},
    3664         955 :                         {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program."},
    3665         955 :                         {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program."},
    3666         955 :                         {RPCResult::Type::STR, "script", /* optional */ true, "The output script type. Only if isscript is true and the redeemscript is known. Possible\n"
    3667             :             "                                                         types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash,\n"
    3668             :                             "witness_v0_scripthash, witness_unknown."},
    3669         955 :                         {RPCResult::Type::STR_HEX, "hex", /* optional */ true, "The redeemscript for the p2sh address."},
    3670        1910 :                         {RPCResult::Type::ARR, "pubkeys", /* optional */ true, "Array of pubkeys associated with the known redeemscript (only if script is multisig).",
    3671        1910 :                         {
    3672         955 :                             {RPCResult::Type::STR, "pubkey", ""},
    3673             :                         }},
    3674         955 :                         {RPCResult::Type::NUM, "sigsrequired", /* optional */ true, "The number of signatures required to spend multisig output (only if script is multisig)."},
    3675         955 :                         {RPCResult::Type::STR_HEX, "pubkey", /* optional */ true, "The hex value of the raw public key for single-key addresses (possibly embedded in P2SH or P2WSH)."},
    3676        1910 :                         {RPCResult::Type::OBJ, "embedded", /* optional */ true, "Information about the address embedded in P2SH or P2WSH, if relevant and known.",
    3677        1910 :                         {
    3678         955 :                             {RPCResult::Type::ELISION, "", "Includes all getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath, hdseedid)\n"
    3679             :                             "and relation to the wallet (ismine, iswatchonly)."},
    3680             :                         }},
    3681         955 :                         {RPCResult::Type::BOOL, "iscompressed", /* optional */ true, "If the pubkey is compressed."},
    3682         955 :                         {RPCResult::Type::NUM_TIME, "timestamp", /* optional */ true, "The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + "."},
    3683         955 :                         {RPCResult::Type::STR, "hdkeypath", /* optional */ true, "The HD keypath, if the key is HD and available."},
    3684         955 :                         {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "The Hash160 of the HD seed."},
    3685         955 :                         {RPCResult::Type::STR_HEX, "hdmasterfingerprint", /* optional */ true, "The fingerprint of the master key."},
    3686        1910 :                         {RPCResult::Type::ARR, "labels", "Array of labels associated with the address. Currently limited to one label but returned\n"
    3687             :                             "as an array to keep the API stable if multiple labels are enabled in the future.",
    3688        1910 :                         {
    3689         955 :                             {RPCResult::Type::STR, "label name", "Label name (defaults to \"\")."},
    3690             :                         }},
    3691             :                     }
    3692             :                 },
    3693         955 :                 RPCExamples{
    3694        1910 :                     HelpExampleCli("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
    3695         955 :                     HelpExampleRpc("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"")
    3696             :                 },
    3697         955 :             }.Check(request);
    3698             : 
    3699         951 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3700         951 :     if (!wallet) return NullUniValue;
    3701         951 :     const CWallet* const pwallet = wallet.get();
    3702             : 
    3703         951 :     LOCK(pwallet->cs_wallet);
    3704             : 
    3705         951 :     UniValue ret(UniValue::VOBJ);
    3706         951 :     CTxDestination dest = DecodeDestination(request.params[0].get_str());
    3707             :     // Make sure the destination is valid
    3708         951 :     if (!IsValidDestination(dest)) {
    3709           2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
    3710             :     }
    3711             : 
    3712         949 :     std::string currentAddress = EncodeDestination(dest);
    3713         949 :     ret.pushKV("address", currentAddress);
    3714             : 
    3715         949 :     CScript scriptPubKey = GetScriptForDestination(dest);
    3716         949 :     ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
    3717             : 
    3718         949 :     std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
    3719             : 
    3720         949 :     isminetype mine = pwallet->IsMine(dest);
    3721         949 :     ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
    3722             : 
    3723         949 :     bool solvable = provider && IsSolvable(*provider, scriptPubKey);
    3724         949 :     ret.pushKV("solvable", solvable);
    3725             : 
    3726         949 :     if (solvable) {
    3727         854 :        ret.pushKV("desc", InferDescriptor(scriptPubKey, *provider)->ToString());
    3728         854 :     }
    3729             : 
    3730         949 :     ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
    3731             : 
    3732         949 :     UniValue detail = DescribeWalletAddress(pwallet, dest);
    3733         949 :     ret.pushKVs(detail);
    3734             : 
    3735         949 :     ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
    3736             : 
    3737         949 :     ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
    3738         949 :     if (spk_man) {
    3739        1616 :         if (const std::unique_ptr<CKeyMetadata> meta = spk_man->GetMetadata(dest)) {
    3740         745 :             ret.pushKV("timestamp", meta->nCreateTime);
    3741         745 :             if (meta->has_key_origin) {
    3742         691 :                 ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
    3743         691 :                 ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
    3744         691 :                 ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint));
    3745         691 :             }
    3746             :         }
    3747         871 :     }
    3748             : 
    3749             :     // Return a `labels` array containing the label associated with the address,
    3750             :     // equivalent to the `label` field above. Currently only one label can be
    3751             :     // associated with an address, but we return an array so the API remains
    3752             :     // stable if we allow multiple labels to be associated with an address in
    3753             :     // the future.
    3754         949 :     UniValue labels(UniValue::VARR);
    3755         949 :     const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
    3756         949 :     if (address_book_entry) {
    3757         798 :         labels.push_back(address_book_entry->GetLabel());
    3758             :     }
    3759         949 :     ret.pushKV("labels", std::move(labels));
    3760             : 
    3761         949 :     return ret;
    3762         999 : }
    3763             : 
    3764          83 : static UniValue getaddressesbylabel(const JSONRPCRequest& request)
    3765             : {
    3766         259 :             RPCHelpMan{"getaddressesbylabel",
    3767          83 :                 "\nReturns the list of addresses assigned the specified label.\n",
    3768         166 :                 {
    3769          83 :                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."},
    3770             :                 },
    3771          83 :                 RPCResult{
    3772          83 :                     RPCResult::Type::OBJ_DYN, "", "json object with addresses as keys",
    3773         166 :                     {
    3774         166 :                         {RPCResult::Type::OBJ, "address", "json object with information about address",
    3775         166 :                         {
    3776          83 :                             {RPCResult::Type::STR, "purpose", "Purpose of address (\"send\" for sending address, \"receive\" for receiving address)"},
    3777             :                         }},
    3778             :                     }
    3779             :                 },
    3780          83 :                 RPCExamples{
    3781          83 :                     HelpExampleCli("getaddressesbylabel", "\"tabby\"")
    3782          83 :             + HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
    3783             :                 },
    3784          83 :             }.Check(request);
    3785             : 
    3786          79 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3787          79 :     if (!wallet) return NullUniValue;
    3788          79 :     const CWallet* const pwallet = wallet.get();
    3789             : 
    3790          79 :     LOCK(pwallet->cs_wallet);
    3791             : 
    3792          79 :     std::string label = LabelFromValue(request.params[0]);
    3793             : 
    3794             :     // Find all addresses that have the given label
    3795          79 :     UniValue ret(UniValue::VOBJ);
    3796          79 :     std::set<std::string> addresses;
    3797        1468 :     for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->m_address_book) {
    3798        1389 :         if (item.second.IsChange()) continue;
    3799        1389 :         if (item.second.GetLabel() == label) {
    3800         144 :             std::string address = EncodeDestination(item.first);
    3801             :             // CWallet::m_address_book is not expected to contain duplicate
    3802             :             // address strings, but build a separate set as a precaution just in
    3803             :             // case it does.
    3804         144 :             bool unique = addresses.emplace(address).second;
    3805         144 :             CHECK_NONFATAL(unique);
    3806             :             // UniValue::pushKV checks if the key exists in O(N)
    3807             :             // and since duplicate addresses are unexpected (checked with
    3808             :             // std::set in O(log(N))), UniValue::__pushKV is used instead,
    3809             :             // which currently is O(1).
    3810         144 :             ret.__pushKV(address, AddressBookDataToJSON(item.second, false));
    3811         144 :         }
    3812        1389 :     }
    3813             : 
    3814          79 :     if (ret.empty()) {
    3815          10 :         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));
    3816             :     }
    3817             : 
    3818          69 :     return ret;
    3819         111 : }
    3820             : 
    3821          77 : static UniValue listlabels(const JSONRPCRequest& request)
    3822             : {
    3823         231 :             RPCHelpMan{"listlabels",
    3824          77 :                 "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
    3825         154 :                 {
    3826          77 :                     {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
    3827             :                 },
    3828          77 :                 RPCResult{
    3829          77 :                     RPCResult::Type::ARR, "", "",
    3830         154 :                     {
    3831          77 :                         {RPCResult::Type::STR, "label", "Label name"},
    3832             :                     }
    3833             :                 },
    3834          77 :                 RPCExamples{
    3835          77 :             "\nList all labels\n"
    3836          77 :             + HelpExampleCli("listlabels", "") +
    3837             :             "\nList labels that have receiving addresses\n"
    3838          77 :             + HelpExampleCli("listlabels", "receive") +
    3839             :             "\nList labels that have sending addresses\n"
    3840          77 :             + HelpExampleCli("listlabels", "send") +
    3841             :             "\nAs a JSON-RPC call\n"
    3842          77 :             + HelpExampleRpc("listlabels", "receive")
    3843             :                 },
    3844          77 :             }.Check(request);
    3845             : 
    3846          73 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3847          73 :     if (!wallet) return NullUniValue;
    3848          73 :     const CWallet* const pwallet = wallet.get();
    3849             : 
    3850          73 :     LOCK(pwallet->cs_wallet);
    3851             : 
    3852          73 :     std::string purpose;
    3853          73 :     if (!request.params[0].isNull()) {
    3854           0 :         purpose = request.params[0].get_str();
    3855             :     }
    3856             : 
    3857             :     // Add to a set to sort by label name, then insert into Univalue array
    3858          73 :     std::set<std::string> label_set;
    3859        1350 :     for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->m_address_book) {
    3860        1277 :         if (entry.second.IsChange()) continue;
    3861        1277 :         if (purpose.empty() || entry.second.purpose == purpose) {
    3862        1277 :             label_set.insert(entry.second.GetLabel());
    3863        1277 :         }
    3864        1277 :     }
    3865             : 
    3866          73 :     UniValue ret(UniValue::VARR);
    3867         490 :     for (const std::string& name : label_set) {
    3868         417 :         ret.push_back(name);
    3869           0 :     }
    3870             : 
    3871          73 :     return ret;
    3872          97 : }
    3873             : 
    3874        2137 : static RPCHelpMan send()
    3875             : {
    3876       51288 :     return RPCHelpMan{"send",
    3877        2137 :         "\nSend a transaction.\n",
    3878       10685 :         {
    3879        4274 :             {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "a json array with outputs (key-value pairs), where none of the keys are duplicated.\n"
    3880             :                     "That is, each address can only appear once and there can only be one 'data' object.\n"
    3881             :                     "For convenience, a dictionary, which holds the key-value pairs directly, is also accepted.",
    3882        6411 :                 {
    3883        4274 :                     {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    3884        4274 :                         {
    3885        2137 :                             {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
    3886             :                         },
    3887             :                         },
    3888        4274 :                     {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    3889        4274 :                         {
    3890        2137 :                             {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
    3891             :                         },
    3892             :                     },
    3893             :                 },
    3894             :             },
    3895        2137 :             {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
    3896        4274 :             {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
    3897        2137 :                         "       \"" + FeeModes("\"\n\"") + "\""},
    3898        4274 :             {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
    3899       32055 :                 {
    3900        2137 :                     {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."},
    3901        2137 :                     {"add_to_wallet", RPCArg::Type::BOOL, /* default */ "true", "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
    3902        2137 :                     {"change_address", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"},
    3903        2137 :                     {"change_position", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
    3904        2137 :                     {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
    3905        2137 :                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
    3906        4274 :                     {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
    3907        2137 :             "       \"" + FeeModes("\"\n\"") + "\""},
    3908        2137 :                     {"include_watching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n"
    3909             :                                           "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
    3910             :                                           "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
    3911        4274 :                     {"inputs", RPCArg::Type::ARR, /* default */ "empty array", "Specify inputs instead of adding them automatically. A json array of json objects",
    3912        8548 :                         {
    3913        2137 :                             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    3914        2137 :                             {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    3915        2137 :                             {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"},
    3916             :                         },
    3917             :                     },
    3918        2137 :                     {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
    3919        2137 :                     {"lock_unspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
    3920        2137 :                     {"psbt", RPCArg::Type::BOOL,  /* default */ "automatic", "Always return a PSBT, implies add_to_wallet=false."},
    3921        4274 :                     {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n"
    3922             :                     "The fee will be equally deducted from the amount of each specified output.\n"
    3923             :                     "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
    3924             :                     "If no outputs are specified here, the sender pays the fee.",
    3925        4274 :                         {
    3926        2137 :                             {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
    3927             :                         },
    3928             :                     },
    3929        2137 :                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
    3930             :                     "                              Allows this transaction to be replaced by a transaction with higher fees"},
    3931             :                 },
    3932        2137 :                 "options"},
    3933             :         },
    3934        2137 :         RPCResult{
    3935        2137 :             RPCResult::Type::OBJ, "", "",
    3936       10685 :                 {
    3937        2137 :                     {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    3938        2137 :                     {RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of the number of addresses."},
    3939        2137 :                     {RPCResult::Type::STR_HEX, "hex", "If add_to_wallet is false, the hex-encoded raw transaction with signature(s)"},
    3940        2137 :                     {RPCResult::Type::STR, "psbt", "If more signatures are needed, or if add_to_wallet is false, the base64-encoded (partially) signed transaction"}
    3941             :                 }
    3942             :         },
    3943        4274 :         RPCExamples{""
    3944             :         "\nSend with a fee rate of 1 satoshi per byte\n"
    3945        2137 :         + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 sat/b\n" +
    3946             :             "\nCreate a transaction that should confirm the next block, with a specific input, and return result without adding to wallet or broadcasting to the network\n")
    3947        2137 :         + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 economical '{\"add_to_wallet\": false, \"inputs\": [{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\", \"vout\":1}]}'")
    3948             :         },
    3949        2170 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    3950             :         {
    3951          42 :             RPCTypeCheck(request.params, {
    3952          33 :                 UniValueType(), // ARR or OBJ, checked later
    3953          33 :                 UniValue::VNUM,
    3954          33 :                 UniValue::VSTR,
    3955          33 :                 UniValue::VOBJ
    3956             :                 }, true
    3957             :             );
    3958             : 
    3959          33 :             std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    3960          33 :             if (!wallet) return NullUniValue;
    3961          33 :             CWallet* const pwallet = wallet.get();
    3962             : 
    3963          33 :             UniValue options = request.params[3];
    3964          33 :             if (options.exists("feeRate") || options.exists("fee_rate") || options.exists("estimate_mode") || options.exists("conf_target")) {
    3965           6 :                 if (!request.params[1].isNull() || !request.params[2].isNull()) {
    3966           1 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, "Use either conf_target and estimate_mode or the options dictionary to control fee rate");
    3967             :                 }
    3968             :             } else {
    3969          27 :                 options.pushKV("conf_target", request.params[1]);
    3970          27 :                 options.pushKV("estimate_mode", request.params[2]);
    3971             :             }
    3972          32 :             if (!options["conf_target"].isNull() && (options["estimate_mode"].isNull() || (options["estimate_mode"].get_str() == "unset"))) {
    3973           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Specify estimate_mode");
    3974             :             }
    3975          32 :             if (options.exists("changeAddress")) {
    3976           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_address");
    3977             :             }
    3978          32 :             if (options.exists("changePosition")) {
    3979           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_position");
    3980             :             }
    3981          32 :             if (options.exists("includeWatching")) {
    3982           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use include_watching");
    3983             :             }
    3984          32 :             if (options.exists("lockUnspents")) {
    3985           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use lock_unspents");
    3986             :             }
    3987          32 :             if (options.exists("subtractFeeFromOutputs")) {
    3988           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use subtract_fee_from_outputs");
    3989             :             }
    3990             : 
    3991          32 :             const bool psbt_opt_in = options.exists("psbt") && options["psbt"].get_bool();
    3992             : 
    3993          32 :             CAmount fee;
    3994          32 :             int change_position;
    3995          32 :             bool rbf = pwallet->m_signal_rbf;
    3996          32 :             if (options.exists("replaceable")) {
    3997           2 :                 rbf = options["add_to_wallet"].get_bool();
    3998           2 :             }
    3999          32 :             CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf);
    4000          31 :             CCoinControl coin_control;
    4001             :             // Automatically select coins, unless at least one is manually selected. Can
    4002             :             // be overriden by options.add_inputs.
    4003          31 :             coin_control.m_add_inputs = rawTx.vin.size() == 0;
    4004          31 :             FundTransaction(pwallet, rawTx, fee, change_position, options, coin_control);
    4005             : 
    4006             :             bool add_to_wallet = true;
    4007          24 :             if (options.exists("add_to_wallet")) {
    4008          16 :                 add_to_wallet = options["add_to_wallet"].get_bool();
    4009          16 :             }
    4010             : 
    4011             :             // Make a blank psbt
    4012          24 :             PartiallySignedTransaction psbtx(rawTx);
    4013             : 
    4014             :             // Fill transaction with out data and sign
    4015          24 :             bool complete = true;
    4016          24 :             const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_ALL, true, false);
    4017          24 :             if (err != TransactionError::OK) {
    4018           0 :                 throw JSONRPCTransactionError(err);
    4019             :             }
    4020             : 
    4021          24 :             CMutableTransaction mtx;
    4022          24 :             complete = FinalizeAndExtractPSBT(psbtx, mtx);
    4023             : 
    4024          24 :             UniValue result(UniValue::VOBJ);
    4025             : 
    4026             :             // Serialize the PSBT
    4027          24 :             CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    4028          24 :             ssTx << psbtx;
    4029          24 :             const std::string result_str = EncodeBase64(ssTx.str());
    4030             : 
    4031          24 :             if (psbt_opt_in || !complete || !add_to_wallet) {
    4032          18 :                 result.pushKV("psbt", result_str);
    4033          18 :             }
    4034             : 
    4035          24 :             if (complete) {
    4036          21 :                 std::string err_string;
    4037          21 :                 std::string hex = EncodeHexTx(CTransaction(mtx));
    4038          21 :                 CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
    4039          21 :                 result.pushKV("txid", tx->GetHash().GetHex());
    4040          21 :                 if (add_to_wallet && !psbt_opt_in) {
    4041           6 :                     pwallet->CommitTransaction(tx, {}, {} /* orderForm */);
    4042           6 :                 } else {
    4043          15 :                     result.pushKV("hex", hex);
    4044             :                 }
    4045          21 :             }
    4046          24 :             result.pushKV("complete", complete);
    4047             : 
    4048          24 :             return result;
    4049          33 :         }
    4050             :     };
    4051           0 : }
    4052             : 
    4053          23 : UniValue sethdseed(const JSONRPCRequest& request)
    4054             : {
    4055          98 :             RPCHelpMan{"sethdseed",
    4056             :                 "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
    4057             :                 "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
    4058          23 :                 "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." +
    4059             :         HELP_REQUIRING_PASSPHRASE,
    4060          74 :                 {
    4061          23 :                     {"newkeypool", RPCArg::Type::BOOL, /* default */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
    4062             :             "                             If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
    4063             :             "                             If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
    4064             :             "                             keypool will be used until it has been depleted."},
    4065          23 :                     {"seed", RPCArg::Type::STR, /* default */ "random seed", "The WIF private key to use as the new HD seed.\n"
    4066             :             "                             The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
    4067             :                 },
    4068          23 :                 RPCResult{RPCResult::Type::NONE, "", ""},
    4069          23 :                 RPCExamples{
    4070          23 :                     HelpExampleCli("sethdseed", "")
    4071          23 :             + HelpExampleCli("sethdseed", "false")
    4072          23 :             + HelpExampleCli("sethdseed", "true \"wifkey\"")
    4073          23 :             + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
    4074             :                 },
    4075          23 :             }.Check(request);
    4076             : 
    4077          18 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    4078          18 :     if (!wallet) return NullUniValue;
    4079          18 :     CWallet* const pwallet = wallet.get();
    4080             : 
    4081          18 :     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
    4082             : 
    4083          17 :     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
    4084           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
    4085             :     }
    4086             : 
    4087          17 :     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
    4088             : 
    4089             :     // Do not do anything to non-HD wallets
    4090          17 :     if (!pwallet->CanSupportFeature(FEATURE_HD)) {
    4091           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD");
    4092             :     }
    4093             : 
    4094          17 :     EnsureWalletIsUnlocked(pwallet);
    4095             : 
    4096             :     bool flush_key_pool = true;
    4097          17 :     if (!request.params[0].isNull()) {
    4098          11 :         flush_key_pool = request.params[0].get_bool();
    4099          10 :     }
    4100             : 
    4101          16 :     CPubKey master_pub_key;
    4102          16 :     if (request.params[1].isNull()) {
    4103           7 :         master_pub_key = spk_man.GenerateNewSeed();
    4104           7 :     } else {
    4105           9 :         CKey key = DecodeSecret(request.params[1].get_str());
    4106           8 :         if (!key.IsValid()) {
    4107           1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
    4108             :         }
    4109             : 
    4110           7 :         if (HaveKey(spk_man, key)) {
    4111           2 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
    4112             :         }
    4113             : 
    4114           5 :         master_pub_key = spk_man.DeriveNewSeed(key);
    4115           9 :     }
    4116             : 
    4117          12 :     spk_man.SetHDSeed(master_pub_key);
    4118          12 :     if (flush_key_pool) spk_man.NewKeyPool();
    4119             : 
    4120          12 :     return NullUniValue;
    4121          47 : }
    4122             : 
    4123         119 : UniValue walletprocesspsbt(const JSONRPCRequest& request)
    4124             : {
    4125         837 :             RPCHelpMan{"walletprocesspsbt",
    4126             :                 "\nUpdate a PSBT with input information from our wallet and then sign inputs\n"
    4127         119 :                 "that we can sign for." +
    4128             :         HELP_REQUIRING_PASSPHRASE,
    4129         599 :                 {
    4130         119 :                     {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
    4131         119 :                     {"sign", RPCArg::Type::BOOL, /* default */ "true", "Also sign the transaction when updating"},
    4132         119 :                     {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
    4133             :             "       \"ALL\"\n"
    4134             :             "       \"NONE\"\n"
    4135             :             "       \"SINGLE\"\n"
    4136             :             "       \"ALL|ANYONECANPAY\"\n"
    4137             :             "       \"NONE|ANYONECANPAY\"\n"
    4138             :             "       \"SINGLE|ANYONECANPAY\""},
    4139         119 :                     {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
    4140             :                 },
    4141         119 :                 RPCResult{
    4142         119 :                     RPCResult::Type::OBJ, "", "",
    4143         361 :                     {
    4144         119 :                         {RPCResult::Type::STR, "psbt", "The base64-encoded partially signed transaction"},
    4145         119 :                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    4146             :                     }
    4147             :                 },
    4148         119 :                 RPCExamples{
    4149         119 :                     HelpExampleCli("walletprocesspsbt", "\"psbt\"")
    4150             :                 },
    4151         119 :             }.Check(request);
    4152             : 
    4153         115 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    4154         115 :     if (!wallet) return NullUniValue;
    4155         115 :     const CWallet* const pwallet = wallet.get();
    4156             : 
    4157         115 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
    4158             : 
    4159             :     // Unserialize the transaction
    4160         115 :     PartiallySignedTransaction psbtx;
    4161         115 :     std::string error;
    4162         115 :     if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
    4163           2 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
    4164             :     }
    4165             : 
    4166             :     // Get the sighash type
    4167         113 :     int nHashType = ParseSighashString(request.params[2]);
    4168             : 
    4169             :     // Fill transaction with our data and also sign
    4170         113 :     bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
    4171         113 :     bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
    4172         113 :     bool complete = true;
    4173         113 :     const TransactionError err = pwallet->FillPSBT(psbtx, complete, nHashType, sign, bip32derivs);
    4174         113 :     if (err != TransactionError::OK) {
    4175           2 :         throw JSONRPCTransactionError(err);
    4176             :     }
    4177             : 
    4178         111 :     UniValue result(UniValue::VOBJ);
    4179         111 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    4180         111 :     ssTx << psbtx;
    4181         111 :     result.pushKV("psbt", EncodeBase64(ssTx.str()));
    4182         111 :     result.pushKV("complete", complete);
    4183             : 
    4184         111 :     return result;
    4185         153 : }
    4186             : 
    4187          59 : UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
    4188             : {
    4189        1308 :             RPCHelpMan{"walletcreatefundedpsbt",
    4190          59 :                 "\nCreates and funds a transaction in the Partially Signed Transaction format.\n"
    4191             :                 "Implements the Creator and Updater roles.\n",
    4192         414 :                 {
    4193         118 :                     {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Leave empty to add inputs automatically. See add_inputs option.",
    4194         118 :                         {
    4195         118 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    4196         240 :                                 {
    4197          59 :                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    4198          59 :                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    4199          59 :                                     {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'locktime' and 'options.replaceable' arguments", "The sequence number"},
    4200             :                                 },
    4201             :                             },
    4202             :                         },
    4203             :                         },
    4204         118 :                     {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
    4205             :                             "That is, each address can only appear once and there can only be one 'data' object.\n"
    4206             :                             "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
    4207             :                             "                             accepted as second parameter.",
    4208         189 :                         {
    4209         118 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    4210         118 :                                 {
    4211          59 :                                     {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
    4212             :                                 },
    4213             :                                 },
    4214         118 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    4215         118 :                                 {
    4216          59 :                                     {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
    4217             :                                 },
    4218             :                             },
    4219             :                         },
    4220             :                     },
    4221          59 :                     {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
    4222         118 :                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
    4223         720 :                         {
    4224          59 :                             {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."},
    4225          59 :                             {"changeAddress", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"},
    4226          59 :                             {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
    4227          59 :                             {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
    4228          59 :                             {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only"},
    4229          59 :                             {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
    4230          59 :                             {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
    4231         118 :                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The outputs to subtract the fee from.\n"
    4232             :                             "                              The fee will be equally deducted from the amount of each specified output.\n"
    4233             :                             "                              Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
    4234             :                             "                              If no outputs are specified here, the sender pays the fee.",
    4235         118 :                                 {
    4236          59 :                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
    4237             :                                 },
    4238             :                             },
    4239          59 :                             {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
    4240             :                             "                              Allows this transaction to be replaced by a transaction with higher fees"},
    4241          59 :                             {"conf_target", RPCArg::Type::NUM, /* default */ "fall back to wallet's confirmation target (txconfirmtarget)", "Confirmation target (in blocks)"},
    4242         118 :                             {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
    4243          59 :                             "         \"" + FeeModes("\"\n\"") + "\""},
    4244             :                         },
    4245          59 :                         "options"},
    4246          59 :                     {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
    4247             :                 },
    4248          59 :                 RPCResult{
    4249          59 :                     RPCResult::Type::OBJ, "", "",
    4250         240 :                     {
    4251          59 :                         {RPCResult::Type::STR, "psbt", "The resulting raw transaction (base64-encoded string)"},
    4252          59 :                         {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
    4253          59 :                         {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
    4254             :                     }
    4255             :                                 },
    4256          59 :                                 RPCExamples{
    4257             :                             "\nCreate a transaction with no inputs\n"
    4258          59 :                             + HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
    4259             :                                 },
    4260          59 :                             }.Check(request);
    4261             : 
    4262          55 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    4263          55 :     if (!wallet) return NullUniValue;
    4264          55 :     CWallet* const pwallet = wallet.get();
    4265             : 
    4266          55 :     RPCTypeCheck(request.params, {
    4267          55 :         UniValue::VARR,
    4268          55 :         UniValueType(), // ARR or OBJ, checked later
    4269          55 :         UniValue::VNUM,
    4270          55 :         UniValue::VOBJ,
    4271          55 :         UniValue::VBOOL
    4272             :         }, true
    4273             :     );
    4274             : 
    4275          55 :     CAmount fee;
    4276          55 :     int change_position;
    4277          55 :     bool rbf = pwallet->m_signal_rbf;
    4278          55 :     const UniValue &replaceable_arg = request.params[3]["replaceable"];
    4279          55 :     if (!replaceable_arg.isNull()) {
    4280           4 :         RPCTypeCheckArgument(replaceable_arg, UniValue::VBOOL);
    4281           4 :         rbf = replaceable_arg.isTrue();
    4282           4 :     }
    4283          55 :     CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
    4284          55 :     CCoinControl coin_control;
    4285             :     // Automatically select coins, unless at least one is manually selected. Can
    4286             :     // be overridden by options.add_inputs.
    4287          55 :     coin_control.m_add_inputs = rawTx.vin.size() == 0;
    4288          55 :     FundTransaction(pwallet, rawTx, fee, change_position, request.params[3], coin_control);
    4289             : 
    4290             :     // Make a blank psbt
    4291          45 :     PartiallySignedTransaction psbtx(rawTx);
    4292             : 
    4293             :     // Fill transaction with out data but don't sign
    4294          45 :     bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
    4295          45 :     bool complete = true;
    4296          45 :     const TransactionError err = pwallet->FillPSBT(psbtx, complete, 1, false, bip32derivs);
    4297          45 :     if (err != TransactionError::OK) {
    4298           0 :         throw JSONRPCTransactionError(err);
    4299             :     }
    4300             : 
    4301             :     // Serialize the PSBT
    4302          45 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    4303          45 :     ssTx << psbtx;
    4304             : 
    4305          45 :     UniValue result(UniValue::VOBJ);
    4306          45 :     result.pushKV("psbt", EncodeBase64(ssTx.str()));
    4307          45 :     result.pushKV("fee", ValueFromAmount(fee));
    4308          45 :     result.pushKV("changepos", change_position);
    4309          45 :     return result;
    4310         227 : }
    4311             : 
    4312           6 : static UniValue upgradewallet(const JSONRPCRequest& request)
    4313             : {
    4314          18 :     RPCHelpMan{"upgradewallet",
    4315           6 :         "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified\n"
    4316             :         "New keys may be generated and a new wallet backup will need to be made.",
    4317          12 :         {
    4318           6 :             {"version", RPCArg::Type::NUM, /* default */ strprintf("%d", FEATURE_LATEST), "The version number to upgrade to. Default is the latest wallet version"}
    4319             :         },
    4320           6 :         RPCResults{},
    4321           6 :         RPCExamples{
    4322           6 :             HelpExampleCli("upgradewallet", "169900")
    4323           6 :             + HelpExampleRpc("upgradewallet", "169900")
    4324             :         }
    4325           6 :     }.Check(request);
    4326             : 
    4327           2 :     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
    4328           2 :     if (!wallet) return NullUniValue;
    4329           2 :     CWallet* const pwallet = wallet.get();
    4330             : 
    4331           2 :     RPCTypeCheck(request.params, {UniValue::VNUM}, true);
    4332             : 
    4333           2 :     EnsureWalletIsUnlocked(pwallet);
    4334             : 
    4335             :     int version = 0;
    4336           2 :     if (!request.params[0].isNull()) {
    4337           1 :         version = request.params[0].get_int();
    4338           1 :     }
    4339             : 
    4340           2 :     bilingual_str error;
    4341           2 :     std::vector<bilingual_str> warnings;
    4342           2 :     if (!pwallet->UpgradeWallet(version, error, warnings)) {
    4343           0 :         throw JSONRPCError(RPC_WALLET_ERROR, error.original);
    4344             :     }
    4345           2 :     return error.original;
    4346          18 : }
    4347             : 
    4348             : RPCHelpMan abortrescan();
    4349             : RPCHelpMan dumpprivkey();
    4350             : RPCHelpMan importprivkey();
    4351             : RPCHelpMan importaddress();
    4352             : RPCHelpMan importpubkey();
    4353             : RPCHelpMan dumpwallet();
    4354             : RPCHelpMan importwallet();
    4355             : RPCHelpMan importprunedfunds();
    4356             : RPCHelpMan removeprunedfunds();
    4357             : RPCHelpMan importmulti();
    4358             : RPCHelpMan importdescriptors();
    4359             : 
    4360         531 : Span<const CRPCCommand> GetWalletRPCCommands()
    4361             : {
    4362             : // clang-format off
    4363        1056 : static const CRPCCommand commands[] =
    4364        6825 : { //  category              name                                actor (function)                argNames
    4365             :     //  --------------------- ------------------------          -----------------------         ----------
    4366         525 :     { "rawtransactions",    "fundrawtransaction",               &fundrawtransaction,            {"hexstring","options","iswitness"} },
    4367         525 :     { "wallet",             "abandontransaction",               &abandontransaction,            {"txid"} },
    4368         525 :     { "wallet",             "abortrescan",                      &abortrescan,                   {} },
    4369         525 :     { "wallet",             "addmultisigaddress",               &addmultisigaddress,            {"nrequired","keys","label","address_type"} },
    4370         525 :     { "wallet",             "backupwallet",                     &backupwallet,                  {"destination"} },
    4371         525 :     { "wallet",             "bumpfee",                          &bumpfee,                       {"txid", "options"} },
    4372         525 :     { "wallet",             "psbtbumpfee",                      &psbtbumpfee,                   {"txid", "options"} },
    4373         525 :     { "wallet",             "createwallet",                     &createwallet,                  {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors", "load_on_startup"} },
    4374         525 :     { "wallet",             "dumpprivkey",                      &dumpprivkey,                   {"address"}  },
    4375         525 :     { "wallet",             "dumpwallet",                       &dumpwallet,                    {"filename"} },
    4376         525 :     { "wallet",             "encryptwallet",                    &encryptwallet,                 {"passphrase"} },
    4377         525 :     { "wallet",             "getaddressesbylabel",              &getaddressesbylabel,           {"label"} },
    4378         525 :     { "wallet",             "getaddressinfo",                   &getaddressinfo,                {"address"} },
    4379         525 :     { "wallet",             "getbalance",                       &getbalance,                    {"dummy","minconf","include_watchonly","avoid_reuse"} },
    4380         525 :     { "wallet",             "getnewaddress",                    &getnewaddress,                 {"label","address_type"} },
    4381         525 :     { "wallet",             "getrawchangeaddress",              &getrawchangeaddress,           {"address_type"} },
    4382         525 :     { "wallet",             "getreceivedbyaddress",             &getreceivedbyaddress,          {"address","minconf"} },
    4383         525 :     { "wallet",             "getreceivedbylabel",               &getreceivedbylabel,            {"label","minconf"} },
    4384         525 :     { "wallet",             "gettransaction",                   &gettransaction,                {"txid","include_watchonly","verbose"} },
    4385         525 :     { "wallet",             "getunconfirmedbalance",            &getunconfirmedbalance,         {} },
    4386         525 :     { "wallet",             "getbalances",                      &getbalances,                   {} },
    4387         525 :     { "wallet",             "getwalletinfo",                    &getwalletinfo,                 {} },
    4388         525 :     { "wallet",             "importaddress",                    &importaddress,                 {"address","label","rescan","p2sh"} },
    4389         525 :     { "wallet",             "importdescriptors",                &importdescriptors,             {"requests"} },
    4390         525 :     { "wallet",             "importmulti",                      &importmulti,                   {"requests","options"} },
    4391         525 :     { "wallet",             "importprivkey",                    &importprivkey,                 {"privkey","label","rescan"} },
    4392         525 :     { "wallet",             "importprunedfunds",                &importprunedfunds,             {"rawtransaction","txoutproof"} },
    4393         525 :     { "wallet",             "importpubkey",                     &importpubkey,                  {"pubkey","label","rescan"} },
    4394         525 :     { "wallet",             "importwallet",                     &importwallet,                  {"filename"} },
    4395         525 :     { "wallet",             "keypoolrefill",                    &keypoolrefill,                 {"newsize"} },
    4396         525 :     { "wallet",             "listaddressgroupings",             &listaddressgroupings,          {} },
    4397         525 :     { "wallet",             "listlabels",                       &listlabels,                    {"purpose"} },
    4398         525 :     { "wallet",             "listlockunspent",                  &listlockunspent,               {} },
    4399         525 :     { "wallet",             "listreceivedbyaddress",            &listreceivedbyaddress,         {"minconf","include_empty","include_watchonly","address_filter"} },
    4400         525 :     { "wallet",             "listreceivedbylabel",              &listreceivedbylabel,           {"minconf","include_empty","include_watchonly"} },
    4401         525 :     { "wallet",             "listsinceblock",                   &listsinceblock,                {"blockhash","target_confirmations","include_watchonly","include_removed"} },
    4402         525 :     { "wallet",             "listtransactions",                 &listtransactions,              {"label|dummy","count","skip","include_watchonly"} },
    4403         525 :     { "wallet",             "listunspent",                      &listunspent,                   {"minconf","maxconf","addresses","include_unsafe","query_options"} },
    4404         525 :     { "wallet",             "listwalletdir",                    &listwalletdir,                 {} },
    4405         525 :     { "wallet",             "listwallets",                      &listwallets,                   {} },
    4406         525 :     { "wallet",             "loadwallet",                       &loadwallet,                    {"filename", "load_on_startup"} },
    4407         525 :     { "wallet",             "lockunspent",                      &lockunspent,                   {"unlock","transactions"} },
    4408         525 :     { "wallet",             "removeprunedfunds",                &removeprunedfunds,             {"txid"} },
    4409         525 :     { "wallet",             "rescanblockchain",                 &rescanblockchain,              {"start_height", "stop_height"} },
    4410         525 :     { "wallet",             "send",                             &send,                          {"outputs","conf_target","estimate_mode","options"} },
    4411         525 :     { "wallet",             "sendmany",                         &sendmany,                      {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
    4412         525 :     { "wallet",             "sendtoaddress",                    &sendtoaddress,                 {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse"} },
    4413         525 :     { "wallet",             "sethdseed",                        &sethdseed,                     {"newkeypool","seed"} },
    4414         525 :     { "wallet",             "setlabel",                         &setlabel,                      {"address","label"} },
    4415         525 :     { "wallet",             "settxfee",                         &settxfee,                      {"amount"} },
    4416         525 :     { "wallet",             "setwalletflag",                    &setwalletflag,                 {"flag","value"} },
    4417         525 :     { "wallet",             "signmessage",                      &signmessage,                   {"address","message"} },
    4418         525 :     { "wallet",             "signrawtransactionwithwallet",     &signrawtransactionwithwallet,  {"hexstring","prevtxs","sighashtype"} },
    4419         525 :     { "wallet",             "unloadwallet",                     &unloadwallet,                  {"wallet_name", "load_on_startup"} },
    4420         525 :     { "wallet",             "upgradewallet",                    &upgradewallet,                 {"version"} },
    4421         525 :     { "wallet",             "walletcreatefundedpsbt",           &walletcreatefundedpsbt,        {"inputs","outputs","locktime","options","bip32derivs"} },
    4422         525 :     { "wallet",             "walletlock",                       &walletlock,                    {} },
    4423         525 :     { "wallet",             "walletpassphrase",                 &walletpassphrase,              {"passphrase","timeout"} },
    4424         525 :     { "wallet",             "walletpassphrasechange",           &walletpassphrasechange,        {"oldpassphrase","newpassphrase"} },
    4425         525 :     { "wallet",             "walletprocesspsbt",                &walletprocesspsbt,             {"psbt","sign","sighashtype","bip32derivs"} },
    4426             : };
    4427             : // clang-format on
    4428         531 :     return MakeSpan(commands);
    4429       31500 : }

Generated by: LCOV version 1.15