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