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