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