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