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