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