LCOV - code coverage report
Current view: top level - src/wallet/rpc - wallet.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 20 612 3.3 %
Date: 2023-09-26 12:08:55 Functions: 10 36 27.8 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2022 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 <core_io.h>
       7             : #include <key_io.h>
       8             : #include <rpc/server.h>
       9             : #include <rpc/util.h>
      10             : #include <util/translation.h>
      11             : #include <wallet/context.h>
      12             : #include <wallet/receive.h>
      13             : #include <wallet/rpc/wallet.h>
      14             : #include <wallet/rpc/util.h>
      15             : #include <wallet/wallet.h>
      16             : #include <wallet/walletutil.h>
      17         173 : 
      18         173 : #include <optional>
      19             : 
      20             : #include <univalue.h>
      21             : 
      22             : 
      23             : namespace wallet {
      24             : 
      25         173 : static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{
      26         173 :     {WALLET_FLAG_AVOID_REUSE,
      27         173 :      "You need to rescan the blockchain in order to correctly mark used "
      28         519 :      "destinations in the past. Until this is done, some destinations may "
      29         173 :      "be considered unused, even if the opposite is the case."},
      30         173 : };
      31             : 
      32             : /** Checks if a CKey is in the given CWallet compressed or otherwise*/
      33           0 : bool HaveKey(const SigningProvider& wallet, const CKey& key)
      34             : {
      35           0 :     CKey key2;
      36           0 :     key2.Set(key.begin(), key.end(), !key.IsCompressed());
      37           0 :     return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
      38           0 : }
      39             : 
      40           0 : static RPCHelpMan getwalletinfo()
      41             : {
      42           0 :     return RPCHelpMan{"getwalletinfo",
      43           0 :                 "Returns an object containing various wallet state info.\n",
      44           0 :                 {},
      45           0 :                 RPCResult{
      46           0 :                     RPCResult::Type::OBJ, "", "",
      47           0 :                     {
      48           0 :                         {
      49           0 :                         {RPCResult::Type::STR, "walletname", "the wallet name"},
      50           0 :                         {RPCResult::Type::NUM, "walletversion", "the wallet version"},
      51           0 :                         {RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"},
      52           0 :                         {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
      53           0 :                         {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
      54           0 :                         {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
      55           0 :                         {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
      56           0 :                         {RPCResult::Type::NUM_TIME, "keypoololdest", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
      57           0 :                         {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
      58           0 :                         {RPCResult::Type::NUM, "keypoolsize_hd_internal", /*optional=*/true, "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
      59           0 :                         {RPCResult::Type::NUM_TIME, "unlocked_until", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
      60           0 :                         {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kvB"},
      61           0 :                         {RPCResult::Type::STR_HEX, "hdseedid", /*optional=*/true, "the Hash160 of the HD seed (only present when HD is enabled)"},
      62           0 :                         {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
      63           0 :                         {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
      64           0 :                         {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
      65           0 :                         {
      66           0 :                             {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
      67           0 :                             {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
      68             :                         }, /*skip_type_check=*/true},
      69           0 :                         {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
      70           0 :                         {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
      71           0 :                         {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
      72           0 :                         RESULT_LAST_PROCESSED_BLOCK,
      73             :                     }},
      74         173 :                 },
      75           0 :                 RPCExamples{
      76           0 :                     HelpExampleCli("getwalletinfo", "")
      77           0 :             + HelpExampleRpc("getwalletinfo", "")
      78             :                 },
      79           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
      80             : {
      81           0 :     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
      82           0 :     if (!pwallet) return UniValue::VNULL;
      83             : 
      84             :     // Make sure the results are valid at least up to the most recent block
      85             :     // the user could have gotten from another RPC command prior to now
      86           0 :     pwallet->BlockUntilSyncedToCurrentChain();
      87             : 
      88           0 :     LOCK(pwallet->cs_wallet);
      89             : 
      90           0 :     UniValue obj(UniValue::VOBJ);
      91         173 : 
      92           0 :     size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
      93           0 :     const auto bal = GetBalance(*pwallet);
      94           0 :     obj.pushKV("walletname", pwallet->GetName());
      95           0 :     obj.pushKV("walletversion", pwallet->GetVersion());
      96           0 :     obj.pushKV("format", pwallet->GetDatabase().Format());
      97           0 :     obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
      98           0 :     obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
      99         173 :     obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
     100           0 :     obj.pushKV("txcount",       (int)pwallet->mapWallet.size());
     101           0 :     const auto kp_oldest = pwallet->GetOldestKeyPoolTime();
     102           0 :     if (kp_oldest.has_value()) {
     103           0 :         obj.pushKV("keypoololdest", kp_oldest.value());
     104           0 :     }
     105           0 :     obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
     106             : 
     107           0 :     LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
     108           0 :     if (spk_man) {
     109           0 :         CKeyID seed_id = spk_man->GetHDChain().seed_id;
     110           0 :         if (!seed_id.IsNull()) {
     111           0 :             obj.pushKV("hdseedid", seed_id.GetHex());
     112           0 :         }
     113           0 :     }
     114             : 
     115           0 :     if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
     116           0 :         obj.pushKV("keypoolsize_hd_internal",   (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
     117           0 :     }
     118           0 :     if (pwallet->IsCrypted()) {
     119           0 :         obj.pushKV("unlocked_until", pwallet->nRelockTime);
     120           0 :     }
     121           0 :     obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
     122           0 :     obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
     123           0 :     obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
     124           0 :     if (pwallet->IsScanning()) {
     125           0 :         UniValue scanning(UniValue::VOBJ);
     126           0 :         scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
     127           0 :         scanning.pushKV("progress", pwallet->ScanningProgress());
     128           0 :         obj.pushKV("scanning", scanning);
     129           0 :     } else {
     130           0 :         obj.pushKV("scanning", false);
     131             :     }
     132           0 :     obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
     133           0 :     obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
     134           0 :     obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
     135             : 
     136           0 :     AppendLastProcessedBlock(obj, *pwallet);
     137           0 :     return obj;
     138           0 : },
     139             :     };
     140           0 : }
     141             : 
     142           0 : static RPCHelpMan listwalletdir()
     143             : {
     144           0 :     return RPCHelpMan{"listwalletdir",
     145           0 :                 "Returns a list of wallets in the wallet directory.\n",
     146           0 :                 {},
     147           0 :                 RPCResult{
     148           0 :                     RPCResult::Type::OBJ, "", "",
     149           0 :                     {
     150           0 :                         {RPCResult::Type::ARR, "wallets", "",
     151           0 :                         {
     152           0 :                             {RPCResult::Type::OBJ, "", "",
     153           0 :                             {
     154           0 :                                 {RPCResult::Type::STR, "name", "The wallet name"},
     155             :                             }},
     156             :                         }},
     157             :                     }
     158             :                 },
     159           0 :                 RPCExamples{
     160           0 :                     HelpExampleCli("listwalletdir", "")
     161           0 :             + HelpExampleRpc("listwalletdir", "")
     162             :                 },
     163         173 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     164         173 : {
     165         173 :     UniValue wallets(UniValue::VARR);
     166         173 :     for (const auto& path : ListDatabases(GetWalletDir())) {
     167         173 :         UniValue wallet(UniValue::VOBJ);
     168         173 :         wallet.pushKV("name", path.u8string());
     169         173 :         wallets.push_back(wallet);
     170         173 :     }
     171             : 
     172           0 :     UniValue result(UniValue::VOBJ);
     173           0 :     result.pushKV("wallets", wallets);
     174           0 :     return result;
     175           0 : },
     176             :     };
     177           0 : }
     178             : 
     179           0 : static RPCHelpMan listwallets()
     180             : {
     181           0 :     return RPCHelpMan{"listwallets",
     182           0 :                 "Returns a list of currently loaded wallets.\n"
     183             :                 "For full information on the wallet, use \"getwalletinfo\"\n",
     184           0 :                 {},
     185           0 :                 RPCResult{
     186           0 :                     RPCResult::Type::ARR, "", "",
     187           0 :                     {
     188           0 :                         {RPCResult::Type::STR, "walletname", "the wallet name"},
     189             :                     }
     190             :                 },
     191           0 :                 RPCExamples{
     192           0 :                     HelpExampleCli("listwallets", "")
     193           0 :             + HelpExampleRpc("listwallets", "")
     194             :                 },
     195           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     196             : {
     197           0 :     UniValue obj(UniValue::VARR);
     198             : 
     199           0 :     WalletContext& context = EnsureWalletContext(request.context);
     200           0 :     for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {
     201           0 :         LOCK(wallet->cs_wallet);
     202           0 :         obj.push_back(wallet->GetName());
     203           0 :     }
     204             : 
     205           0 :     return obj;
     206           0 : },
     207             :     };
     208           0 : }
     209             : 
     210           0 : static RPCHelpMan loadwallet()
     211             : {
     212           0 :     return RPCHelpMan{"loadwallet",
     213           0 :                 "\nLoads a wallet from a wallet file or directory."
     214             :                 "\nNote that all wallet command-line options used when starting bitcoind will be"
     215             :                 "\napplied to the new wallet.\n",
     216           0 :                 {
     217           0 :                     {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
     218           0 :                     {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
     219             :                 },
     220           0 :                 RPCResult{
     221           0 :                     RPCResult::Type::OBJ, "", "",
     222           0 :                     {
     223           0 :                         {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
     224           0 :                         {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",
     225           0 :                         {
     226           0 :                             {RPCResult::Type::STR, "", ""},
     227             :                         }},
     228             :                     }
     229             :                 },
     230           0 :                 RPCExamples{
     231           0 :                     HelpExampleCli("loadwallet", "\"test.dat\"")
     232           0 :             + HelpExampleRpc("loadwallet", "\"test.dat\"")
     233             :                 },
     234           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     235             : {
     236           0 :     WalletContext& context = EnsureWalletContext(request.context);
     237           0 :     const std::string name(request.params[0].get_str());
     238             : 
     239           0 :     DatabaseOptions options;
     240             :     DatabaseStatus status;
     241           0 :     ReadDatabaseArgs(*context.args, options);
     242           0 :     options.require_existing = true;
     243           0 :     bilingual_str error;
     244           0 :     std::vector<bilingual_str> warnings;
     245           0 :     std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
     246             : 
     247             :     {
     248           0 :         LOCK(context.wallets_mutex);
     249           0 :         if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
     250           0 :             throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded.");
     251             :         }
     252           0 :     }
     253             : 
     254           0 :     std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
     255             : 
     256           0 :     HandleWalletError(wallet, status, error);
     257             : 
     258           0 :     UniValue obj(UniValue::VOBJ);
     259           0 :     obj.pushKV("name", wallet->GetName());
     260           0 :     PushWarnings(warnings, obj);
     261             : 
     262           0 :     return obj;
     263           0 : },
     264             :     };
     265           0 : }
     266             : 
     267           0 : static RPCHelpMan setwalletflag()
     268             : {
     269           0 :             std::string flags;
     270         173 :             for (auto& it : WALLET_FLAG_MAP)
     271           0 :                 if (it.second & MUTABLE_WALLET_FLAGS)
     272           0 :                     flags += (flags == "" ? "" : ", ") + it.first;
     273             : 
     274           0 :     return RPCHelpMan{"setwalletflag",
     275           0 :                 "\nChange the state of the given wallet flag for a wallet.\n",
     276           0 :                 {
     277           0 :                     {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
     278           0 :                     {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
     279             :                 },
     280           0 :                 RPCResult{
     281           0 :                     RPCResult::Type::OBJ, "", "",
     282           0 :                     {
     283           0 :                         {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
     284           0 :                         {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
     285           0 :                         {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
     286             :                     }
     287             :                 },
     288           0 :                 RPCExamples{
     289           0 :                     HelpExampleCli("setwalletflag", "avoid_reuse")
     290           0 :                   + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
     291             :                 },
     292           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     293             : {
     294           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     295           0 :     if (!pwallet) return UniValue::VNULL;
     296             : 
     297           0 :     std::string flag_str = request.params[0].get_str();
     298           0 :     bool value = request.params[1].isNull() || request.params[1].get_bool();
     299             : 
     300           0 :     if (!WALLET_FLAG_MAP.count(flag_str)) {
     301           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
     302             :     }
     303             : 
     304           0 :     auto flag = WALLET_FLAG_MAP.at(flag_str);
     305             : 
     306           0 :     if (!(flag & MUTABLE_WALLET_FLAGS)) {
     307           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
     308             :     }
     309             : 
     310           0 :     UniValue res(UniValue::VOBJ);
     311             : 
     312           0 :     if (pwallet->IsWalletFlagSet(flag) == value) {
     313           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
     314             :     }
     315             : 
     316           0 :     res.pushKV("flag_name", flag_str);
     317           0 :     res.pushKV("flag_state", value);
     318             : 
     319           0 :     if (value) {
     320           0 :         pwallet->SetWalletFlag(flag);
     321           0 :     } else {
     322           0 :         pwallet->UnsetWalletFlag(flag);
     323             :     }
     324             : 
     325           0 :     if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
     326           0 :         res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
     327           0 :     }
     328             : 
     329           0 :     return res;
     330           0 : },
     331             :     };
     332           0 : }
     333             : 
     334           0 : static RPCHelpMan createwallet()
     335             : {
     336           0 :     return RPCHelpMan{
     337           0 :         "createwallet",
     338           0 :         "\nCreates and loads a new wallet.\n",
     339           0 :         {
     340           0 :             {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
     341           0 :             {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
     342           0 :             {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
     343           0 :             {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
     344           0 :             {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
     345           0 :             {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."
     346             :                                                                        " Setting to \"false\" will create a legacy wallet; however, the legacy wallet type is being deprecated and"
     347             :                                                                        " support for creating and opening legacy wallets will be removed in the future."},
     348           0 :             {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
     349           0 :             {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
     350             :         },
     351           0 :         RPCResult{
     352           0 :             RPCResult::Type::OBJ, "", "",
     353           0 :             {
     354           0 :                 {RPCResult::Type::STR, "name", "The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path."},
     355           0 :                 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
     356           0 :                 {
     357           0 :                     {RPCResult::Type::STR, "", ""},
     358             :                 }},
     359             :             }
     360             :         },
     361           0 :         RPCExamples{
     362           0 :             HelpExampleCli("createwallet", "\"testwallet\"")
     363           0 :             + HelpExampleRpc("createwallet", "\"testwallet\"")
     364           0 :             + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
     365           0 :             + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
     366             :         },
     367           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     368             : {
     369           0 :     WalletContext& context = EnsureWalletContext(request.context);
     370           0 :     uint64_t flags = 0;
     371           0 :     if (!request.params[1].isNull() && request.params[1].get_bool()) {
     372           0 :         flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
     373           0 :     }
     374             : 
     375           0 :     if (!request.params[2].isNull() && request.params[2].get_bool()) {
     376           0 :         flags |= WALLET_FLAG_BLANK_WALLET;
     377           0 :     }
     378           0 :     SecureString passphrase;
     379           0 :     passphrase.reserve(100);
     380           0 :     std::vector<bilingual_str> warnings;
     381           0 :     if (!request.params[3].isNull()) {
     382           0 :         passphrase = std::string_view{request.params[3].get_str()};
     383           0 :         if (passphrase.empty()) {
     384             :             // Empty string means unencrypted
     385           0 :             warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
     386           0 :         }
     387           0 :     }
     388             : 
     389           0 :     if (!request.params[4].isNull() && request.params[4].get_bool()) {
     390           0 :         flags |= WALLET_FLAG_AVOID_REUSE;
     391           0 :     }
     392           0 :     if (request.params[5].isNull() || request.params[5].get_bool()) {
     393             : #ifndef USE_SQLITE
     394             :         throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
     395             : #endif
     396           0 :         flags |= WALLET_FLAG_DESCRIPTORS;
     397           0 :     }
     398           0 :     if (!request.params[7].isNull() && request.params[7].get_bool()) {
     399             : #ifdef ENABLE_EXTERNAL_SIGNER
     400             :         flags |= WALLET_FLAG_EXTERNAL_SIGNER;
     401             : #else
     402           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
     403             : #endif
     404             :     }
     405             : 
     406             : #ifndef USE_BDB
     407           0 :     if (!(flags & WALLET_FLAG_DESCRIPTORS)) {
     408           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without bdb support (required for legacy wallets)");
     409             :     }
     410             : #endif
     411             : 
     412           0 :     DatabaseOptions options;
     413             :     DatabaseStatus status;
     414           0 :     ReadDatabaseArgs(*context.args, options);
     415           0 :     options.require_create = true;
     416           0 :     options.create_flags = flags;
     417           0 :     options.create_passphrase = passphrase;
     418           0 :     bilingual_str error;
     419           0 :     std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
     420           0 :     const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
     421           0 :     if (!wallet) {
     422           0 :         RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
     423           0 :         throw JSONRPCError(code, error.original);
     424             :     }
     425             : 
     426           0 :     UniValue obj(UniValue::VOBJ);
     427           0 :     obj.pushKV("name", wallet->GetName());
     428           0 :     PushWarnings(warnings, obj);
     429             : 
     430           0 :     return obj;
     431           0 : },
     432             :     };
     433           0 : }
     434             : 
     435           0 : static RPCHelpMan unloadwallet()
     436             : {
     437           0 :     return RPCHelpMan{"unloadwallet",
     438           0 :                 "Unloads the wallet referenced by the request endpoint, otherwise unloads the wallet specified in the argument.\n"
     439             :                 "Specifying the wallet name on a wallet endpoint is invalid.",
     440           0 :                 {
     441           0 :                     {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
     442           0 :                     {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
     443             :                 },
     444           0 :                 RPCResult{RPCResult::Type::OBJ, "", "", {
     445           0 :                     {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
     446           0 :                     {
     447           0 :                         {RPCResult::Type::STR, "", ""},
     448             :                     }},
     449             :                 }},
     450           0 :                 RPCExamples{
     451           0 :                     HelpExampleCli("unloadwallet", "wallet_name")
     452           0 :             + HelpExampleRpc("unloadwallet", "wallet_name")
     453             :                 },
     454           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     455             : {
     456           0 :     std::string wallet_name;
     457           0 :     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
     458           0 :         if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
     459           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
     460             :         }
     461           0 :     } else {
     462           0 :         wallet_name = request.params[0].get_str();
     463             :     }
     464             : 
     465           0 :     WalletContext& context = EnsureWalletContext(request.context);
     466           0 :     std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
     467           0 :     if (!wallet) {
     468           0 :         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
     469             :     }
     470             : 
     471           0 :     std::vector<bilingual_str> warnings;
     472             :     {
     473           0 :         WalletRescanReserver reserver(*wallet);
     474           0 :         if (!reserver.reserve()) {
     475           0 :             throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
     476             :         }
     477             : 
     478             :         // Release the "main" shared pointer and prevent further notifications.
     479             :         // Note that any attempt to load the same wallet would fail until the wallet
     480             :         // is destroyed (see CheckUniqueFileid).
     481           0 :         std::optional<bool> load_on_start{self.MaybeArg<bool>(1)};
     482           0 :         if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
     483           0 :             throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
     484             :         }
     485           0 :     }
     486             : 
     487           0 :     UnloadWallet(std::move(wallet));
     488             : 
     489           0 :     UniValue result(UniValue::VOBJ);
     490           0 :     PushWarnings(warnings, result);
     491             : 
     492           0 :     return result;
     493           0 : },
     494             :     };
     495           0 : }
     496             : 
     497           0 : static RPCHelpMan sethdseed()
     498             : {
     499           0 :     return RPCHelpMan{"sethdseed",
     500             :                 "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
     501             :                 "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
     502           0 :                 "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HELP_REQUIRING_PASSPHRASE +
     503             :                 "Note: This command is only compatible with legacy wallets.\n",
     504           0 :                 {
     505           0 :                     {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
     506             :                                          "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
     507             :                                          "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
     508             :                                          "keypool will be used until it has been depleted."},
     509           0 :                     {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n"
     510             :                                          "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
     511             :                 },
     512           0 :                 RPCResult{RPCResult::Type::NONE, "", ""},
     513           0 :                 RPCExamples{
     514           0 :                     HelpExampleCli("sethdseed", "")
     515           0 :             + HelpExampleCli("sethdseed", "false")
     516           0 :             + HelpExampleCli("sethdseed", "true \"wifkey\"")
     517           0 :             + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
     518             :                 },
     519           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     520             : {
     521           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     522           0 :     if (!pwallet) return UniValue::VNULL;
     523             : 
     524           0 :     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
     525             : 
     526           0 :     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
     527           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
     528             :     }
     529             : 
     530           0 :     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
     531             : 
     532             :     // Do not do anything to non-HD wallets
     533           0 :     if (!pwallet->CanSupportFeature(FEATURE_HD)) {
     534           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set an HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD");
     535             :     }
     536             : 
     537           0 :     EnsureWalletIsUnlocked(*pwallet);
     538             : 
     539           0 :     bool flush_key_pool = true;
     540           0 :     if (!request.params[0].isNull()) {
     541           0 :         flush_key_pool = request.params[0].get_bool();
     542           0 :     }
     543             : 
     544           0 :     CPubKey master_pub_key;
     545           0 :     if (request.params[1].isNull()) {
     546           0 :         master_pub_key = spk_man.GenerateNewSeed();
     547           0 :     } else {
     548           0 :         CKey key = DecodeSecret(request.params[1].get_str());
     549           0 :         if (!key.IsValid()) {
     550           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
     551             :         }
     552             : 
     553           0 :         if (HaveKey(spk_man, key)) {
     554           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
     555             :         }
     556             : 
     557           0 :         master_pub_key = spk_man.DeriveNewSeed(key);
     558           0 :     }
     559             : 
     560           0 :     spk_man.SetHDSeed(master_pub_key);
     561           0 :     if (flush_key_pool) spk_man.NewKeyPool();
     562             : 
     563           0 :     return UniValue::VNULL;
     564           0 : },
     565             :     };
     566           0 : }
     567             : 
     568           0 : static RPCHelpMan upgradewallet()
     569             : {
     570           0 :     return RPCHelpMan{"upgradewallet",
     571           0 :         "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
     572             :         "New keys may be generated and a new wallet backup will need to be made.",
     573           0 :         {
     574           0 :             {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."}
     575             :         },
     576           0 :         RPCResult{
     577           0 :             RPCResult::Type::OBJ, "", "",
     578           0 :             {
     579           0 :                 {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"},
     580           0 :                 {RPCResult::Type::NUM, "previous_version", "Version of wallet before this operation"},
     581           0 :                 {RPCResult::Type::NUM, "current_version", "Version of wallet after this operation"},
     582           0 :                 {RPCResult::Type::STR, "result", /*optional=*/true, "Description of result, if no error"},
     583           0 :                 {RPCResult::Type::STR, "error", /*optional=*/true, "Error message (if there is one)"}
     584             :             },
     585             :         },
     586           0 :         RPCExamples{
     587           0 :             HelpExampleCli("upgradewallet", "169900")
     588           0 :             + HelpExampleRpc("upgradewallet", "169900")
     589             :         },
     590           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     591             : {
     592           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     593           0 :     if (!pwallet) return UniValue::VNULL;
     594             : 
     595           0 :     EnsureWalletIsUnlocked(*pwallet);
     596             : 
     597           0 :     int version = 0;
     598           0 :     if (!request.params[0].isNull()) {
     599           0 :         version = request.params[0].getInt<int>();
     600           0 :     }
     601           0 :     bilingual_str error;
     602           0 :     const int previous_version{pwallet->GetVersion()};
     603           0 :     const bool wallet_upgraded{pwallet->UpgradeWallet(version, error)};
     604           0 :     const int current_version{pwallet->GetVersion()};
     605           0 :     std::string result;
     606             : 
     607           0 :     if (wallet_upgraded) {
     608           0 :         if (previous_version == current_version) {
     609           0 :             result = "Already at latest version. Wallet version unchanged.";
     610           0 :         } else {
     611           0 :             result = strprintf("Wallet upgraded successfully from version %i to version %i.", previous_version, current_version);
     612             :         }
     613           0 :     }
     614             : 
     615           0 :     UniValue obj(UniValue::VOBJ);
     616           0 :     obj.pushKV("wallet_name", pwallet->GetName());
     617           0 :     obj.pushKV("previous_version", previous_version);
     618           0 :     obj.pushKV("current_version", current_version);
     619           0 :     if (!result.empty()) {
     620           0 :         obj.pushKV("result", result);
     621           0 :     } else {
     622           0 :         CHECK_NONFATAL(!error.empty());
     623           0 :         obj.pushKV("error", error.original);
     624             :     }
     625           0 :     return obj;
     626           0 : },
     627             :     };
     628           0 : }
     629             : 
     630           0 : RPCHelpMan simulaterawtransaction()
     631             : {
     632           0 :     return RPCHelpMan{"simulaterawtransaction",
     633           0 :         "\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
     634           0 :         {
     635           0 :             {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of hex strings of raw transactions.\n",
     636           0 :                 {
     637           0 :                     {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
     638             :                 },
     639             :             },
     640           0 :             {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
     641           0 :                 {
     642           0 :                     {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
     643             :                 },
     644             :             },
     645             :         },
     646           0 :         RPCResult{
     647           0 :             RPCResult::Type::OBJ, "", "",
     648           0 :             {
     649           0 :                 {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
     650             :             }
     651             :         },
     652           0 :         RPCExamples{
     653           0 :             HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
     654           0 :             + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
     655             :         },
     656           0 :     [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     657             : {
     658           0 :     const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
     659           0 :     if (!rpc_wallet) return UniValue::VNULL;
     660           0 :     const CWallet& wallet = *rpc_wallet;
     661             : 
     662           0 :     LOCK(wallet.cs_wallet);
     663             : 
     664           0 :     UniValue include_watchonly(UniValue::VNULL);
     665           0 :     if (request.params[1].isObject()) {
     666           0 :         UniValue options = request.params[1];
     667           0 :         RPCTypeCheckObj(options,
     668           0 :             {
     669           0 :                 {"include_watchonly", UniValueType(UniValue::VBOOL)},
     670             :             },
     671             :             true, true);
     672             : 
     673           0 :         include_watchonly = options["include_watchonly"];
     674           0 :     }
     675             : 
     676           0 :     isminefilter filter = ISMINE_SPENDABLE;
     677           0 :     if (ParseIncludeWatchonly(include_watchonly, wallet)) {
     678           0 :         filter |= ISMINE_WATCH_ONLY;
     679           0 :     }
     680             : 
     681           0 :     const auto& txs = request.params[0].get_array();
     682           0 :     CAmount changes{0};
     683           0 :     std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
     684           0 :     std::set<COutPoint> spent;
     685             : 
     686           0 :     for (size_t i = 0; i < txs.size(); ++i) {
     687           0 :         CMutableTransaction mtx;
     688           0 :         if (!DecodeHexTx(mtx, txs[i].get_str(), /* try_no_witness */ true, /* try_witness */ true)) {
     689           0 :             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
     690             :         }
     691             : 
     692             :         // Fetch previous transactions (inputs)
     693           0 :         std::map<COutPoint, Coin> coins;
     694           0 :         for (const CTxIn& txin : mtx.vin) {
     695           0 :             coins[txin.prevout]; // Create empty map entry keyed by prevout.
     696             :         }
     697           0 :         wallet.chain().findCoins(coins);
     698             : 
     699             :         // Fetch debit; we are *spending* these; if the transaction is signed and
     700             :         // broadcast, we will lose everything in these
     701           0 :         for (const auto& txin : mtx.vin) {
     702           0 :             const auto& outpoint = txin.prevout;
     703           0 :             if (spent.count(outpoint)) {
     704           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
     705             :             }
     706           0 :             if (new_utxos.count(outpoint)) {
     707           0 :                 changes -= new_utxos.at(outpoint);
     708           0 :                 new_utxos.erase(outpoint);
     709           0 :             } else {
     710           0 :                 if (coins.at(outpoint).IsSpent()) {
     711           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
     712             :                 }
     713           0 :                 changes -= wallet.GetDebit(txin, filter);
     714             :             }
     715           0 :             spent.insert(outpoint);
     716             :         }
     717             : 
     718             :         // Iterate over outputs; we are *receiving* these, if the wallet considers
     719             :         // them "mine"; if the transaction is signed and broadcast, we will receive
     720             :         // everything in these
     721             :         // Also populate new_utxos in case these are spent in later transactions
     722             : 
     723           0 :         const auto& hash = mtx.GetHash();
     724           0 :         for (size_t i = 0; i < mtx.vout.size(); ++i) {
     725           0 :             const auto& txout = mtx.vout[i];
     726           0 :             bool is_mine = 0 < (wallet.IsMine(txout) & filter);
     727           0 :             changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
     728           0 :         }
     729           0 :     }
     730             : 
     731           0 :     UniValue result(UniValue::VOBJ);
     732           0 :     result.pushKV("balance_change", ValueFromAmount(changes));
     733             : 
     734           0 :     return result;
     735           0 : }
     736             :     };
     737           0 : }
     738             : 
     739           0 : static RPCHelpMan migratewallet()
     740             : {
     741           0 :     return RPCHelpMan{"migratewallet",
     742           0 :         "EXPERIMENTAL warning: This call may not work as expected and may be changed in future releases\n"
     743             :         "\nMigrate the wallet to a descriptor wallet.\n"
     744             :         "A new wallet backup will need to be made.\n"
     745             :         "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
     746             :         "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
     747             :         "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
     748             :         "\nEncrypted wallets must have the passphrase provided as an argument to this call.",
     749           0 :         {
     750           0 :             {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to migrate. If provided both here and in the RPC endpoint, the two must be identical."},
     751           0 :             {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
     752             :         },
     753           0 :         RPCResult{
     754           0 :             RPCResult::Type::OBJ, "", "",
     755           0 :             {
     756           0 :                 {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
     757           0 :                 {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
     758           0 :                 {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
     759           0 :                 {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
     760             :             }
     761             :         },
     762           0 :         RPCExamples{
     763           0 :             HelpExampleCli("migratewallet", "")
     764           0 :             + HelpExampleRpc("migratewallet", "")
     765             :         },
     766           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     767             :         {
     768           0 :             std::string wallet_name;
     769           0 :             if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
     770           0 :                 if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
     771           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
     772             :                 }
     773           0 :             } else {
     774           0 :                 if (request.params[0].isNull()) {
     775           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, "Either RPC endpoint wallet or wallet_name parameter must be provided");
     776             :                 }
     777           0 :                 wallet_name = request.params[0].get_str();
     778             :             }
     779             : 
     780           0 :             SecureString wallet_pass;
     781           0 :             wallet_pass.reserve(100);
     782           0 :             if (!request.params[1].isNull()) {
     783           0 :                 wallet_pass = std::string_view{request.params[1].get_str()};
     784           0 :             }
     785             : 
     786           0 :             WalletContext& context = EnsureWalletContext(request.context);
     787           0 :             util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
     788           0 :             if (!res) {
     789           0 :                 throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
     790             :             }
     791             : 
     792           0 :             UniValue r{UniValue::VOBJ};
     793           0 :             r.pushKV("wallet_name", res->wallet_name);
     794           0 :             if (res->watchonly_wallet) {
     795           0 :                 r.pushKV("watchonly_name", res->watchonly_wallet->GetName());
     796           0 :             }
     797           0 :             if (res->solvables_wallet) {
     798           0 :                 r.pushKV("solvables_name", res->solvables_wallet->GetName());
     799           0 :             }
     800           0 :             r.pushKV("backup_path", res->backup_path.u8string());
     801             : 
     802           0 :             return r;
     803           0 :         },
     804             :     };
     805           0 : }
     806             : 
     807             : // addresses
     808             : RPCHelpMan getaddressinfo();
     809             : RPCHelpMan getnewaddress();
     810             : RPCHelpMan getrawchangeaddress();
     811             : RPCHelpMan setlabel();
     812             : RPCHelpMan listaddressgroupings();
     813             : RPCHelpMan addmultisigaddress();
     814             : RPCHelpMan keypoolrefill();
     815             : RPCHelpMan newkeypool();
     816             : RPCHelpMan getaddressesbylabel();
     817             : RPCHelpMan listlabels();
     818             : #ifdef ENABLE_EXTERNAL_SIGNER
     819             : RPCHelpMan walletdisplayaddress();
     820             : #endif // ENABLE_EXTERNAL_SIGNER
     821             : 
     822             : // backup
     823             : RPCHelpMan dumpprivkey();
     824             : RPCHelpMan importprivkey();
     825             : RPCHelpMan importaddress();
     826             : RPCHelpMan importpubkey();
     827             : RPCHelpMan dumpwallet();
     828             : RPCHelpMan importwallet();
     829             : RPCHelpMan importprunedfunds();
     830             : RPCHelpMan removeprunedfunds();
     831             : RPCHelpMan importmulti();
     832             : RPCHelpMan importdescriptors();
     833             : RPCHelpMan listdescriptors();
     834             : RPCHelpMan backupwallet();
     835             : RPCHelpMan restorewallet();
     836             : 
     837             : // coins
     838             : RPCHelpMan getreceivedbyaddress();
     839             : RPCHelpMan getreceivedbylabel();
     840             : RPCHelpMan getbalance();
     841             : RPCHelpMan getunconfirmedbalance();
     842             : RPCHelpMan lockunspent();
     843             : RPCHelpMan listlockunspent();
     844             : RPCHelpMan getbalances();
     845             : RPCHelpMan listunspent();
     846             : 
     847             : // encryption
     848             : RPCHelpMan walletpassphrase();
     849             : RPCHelpMan walletpassphrasechange();
     850             : RPCHelpMan walletlock();
     851             : RPCHelpMan encryptwallet();
     852             : 
     853             : // spend
     854             : RPCHelpMan sendtoaddress();
     855             : RPCHelpMan sendmany();
     856             : RPCHelpMan settxfee();
     857             : RPCHelpMan fundrawtransaction();
     858             : RPCHelpMan bumpfee();
     859             : RPCHelpMan psbtbumpfee();
     860             : RPCHelpMan send();
     861             : RPCHelpMan sendall();
     862             : RPCHelpMan walletprocesspsbt();
     863             : RPCHelpMan walletcreatefundedpsbt();
     864             : RPCHelpMan signrawtransactionwithwallet();
     865             : 
     866             : // signmessage
     867             : RPCHelpMan signmessage();
     868             : 
     869             : // transactions
     870             : RPCHelpMan listreceivedbyaddress();
     871             : RPCHelpMan listreceivedbylabel();
     872             : RPCHelpMan listtransactions();
     873             : RPCHelpMan listsinceblock();
     874             : RPCHelpMan gettransaction();
     875             : RPCHelpMan abandontransaction();
     876             : RPCHelpMan rescanblockchain();
     877             : RPCHelpMan abortrescan();
     878             : 
     879           0 : Span<const CRPCCommand> GetWalletRPCCommands()
     880             : {
     881           0 :     static const CRPCCommand commands[]{
     882           0 :         {"rawtransactions", &fundrawtransaction},
     883           0 :         {"wallet", &abandontransaction},
     884           0 :         {"wallet", &abortrescan},
     885           0 :         {"wallet", &addmultisigaddress},
     886           0 :         {"wallet", &backupwallet},
     887           0 :         {"wallet", &bumpfee},
     888           0 :         {"wallet", &psbtbumpfee},
     889           0 :         {"wallet", &createwallet},
     890           0 :         {"wallet", &restorewallet},
     891           0 :         {"wallet", &dumpprivkey},
     892           0 :         {"wallet", &dumpwallet},
     893           0 :         {"wallet", &encryptwallet},
     894           0 :         {"wallet", &getaddressesbylabel},
     895           0 :         {"wallet", &getaddressinfo},
     896           0 :         {"wallet", &getbalance},
     897           0 :         {"wallet", &getnewaddress},
     898           0 :         {"wallet", &getrawchangeaddress},
     899           0 :         {"wallet", &getreceivedbyaddress},
     900           0 :         {"wallet", &getreceivedbylabel},
     901           0 :         {"wallet", &gettransaction},
     902           0 :         {"wallet", &getunconfirmedbalance},
     903           0 :         {"wallet", &getbalances},
     904           0 :         {"wallet", &getwalletinfo},
     905           0 :         {"wallet", &importaddress},
     906           0 :         {"wallet", &importdescriptors},
     907           0 :         {"wallet", &importmulti},
     908           0 :         {"wallet", &importprivkey},
     909           0 :         {"wallet", &importprunedfunds},
     910           0 :         {"wallet", &importpubkey},
     911           0 :         {"wallet", &importwallet},
     912           0 :         {"wallet", &keypoolrefill},
     913           0 :         {"wallet", &listaddressgroupings},
     914           0 :         {"wallet", &listdescriptors},
     915           0 :         {"wallet", &listlabels},
     916           0 :         {"wallet", &listlockunspent},
     917           0 :         {"wallet", &listreceivedbyaddress},
     918           0 :         {"wallet", &listreceivedbylabel},
     919           0 :         {"wallet", &listsinceblock},
     920           0 :         {"wallet", &listtransactions},
     921           0 :         {"wallet", &listunspent},
     922           0 :         {"wallet", &listwalletdir},
     923           0 :         {"wallet", &listwallets},
     924           0 :         {"wallet", &loadwallet},
     925           0 :         {"wallet", &lockunspent},
     926           0 :         {"wallet", &migratewallet},
     927           0 :         {"wallet", &newkeypool},
     928           0 :         {"wallet", &removeprunedfunds},
     929           0 :         {"wallet", &rescanblockchain},
     930           0 :         {"wallet", &send},
     931           0 :         {"wallet", &sendmany},
     932           0 :         {"wallet", &sendtoaddress},
     933           0 :         {"wallet", &sethdseed},
     934           0 :         {"wallet", &setlabel},
     935           0 :         {"wallet", &settxfee},
     936           0 :         {"wallet", &setwalletflag},
     937           0 :         {"wallet", &signmessage},
     938           0 :         {"wallet", &signrawtransactionwithwallet},
     939           0 :         {"wallet", &simulaterawtransaction},
     940           0 :         {"wallet", &sendall},
     941           0 :         {"wallet", &unloadwallet},
     942           0 :         {"wallet", &upgradewallet},
     943           0 :         {"wallet", &walletcreatefundedpsbt},
     944             : #ifdef ENABLE_EXTERNAL_SIGNER
     945             :         {"wallet", &walletdisplayaddress},
     946             : #endif // ENABLE_EXTERNAL_SIGNER
     947           0 :         {"wallet", &walletlock},
     948           0 :         {"wallet", &walletpassphrase},
     949           0 :         {"wallet", &walletpassphrasechange},
     950           0 :         {"wallet", &walletprocesspsbt},
     951             :     };
     952           0 :     return commands;
     953           0 : }
     954             : } // namespace wallet

Generated by: LCOV version 1.14