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