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