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