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