LCOV - code coverage report
Current view: top level - src/wallet/rpc - spend.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 18 1096 1.6 %
Date: 2023-09-26 12:08:55 Functions: 9 42 21.4 %

          Line data    Source code
       1             : // Copyright (c) 2011-2022 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <consensus/validation.h>
       6             : #include <core_io.h>
       7             : #include <key_io.h>
       8             : #include <policy/policy.h>
       9             : #include <rpc/rawtransaction_util.h>
      10             : #include <rpc/util.h>
      11             : #include <script/script.h>
      12             : #include <util/fees.h>
      13             : #include <util/rbf.h>
      14             : #include <util/translation.h>
      15             : #include <util/vector.h>
      16             : #include <wallet/coincontrol.h>
      17         173 : #include <wallet/feebumper.h>
      18         173 : #include <wallet/fees.h>
      19             : #include <wallet/rpc/util.h>
      20             : #include <wallet/spend.h>
      21             : #include <wallet/wallet.h>
      22             : 
      23             : #include <univalue.h>
      24             : 
      25             : 
      26             : namespace wallet {
      27         173 : static void ParseRecipients(const UniValue& address_amounts, const UniValue& subtract_fee_outputs, std::vector<CRecipient>& recipients)
      28         519 : {
      29         173 :     std::set<CTxDestination> destinations;
      30         173 :     int i = 0;
      31           0 :     for (const std::string& address: address_amounts.getKeys()) {
      32           0 :         CTxDestination dest = DecodeDestination(address);
      33           0 :         if (!IsValidDestination(dest)) {
      34           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + address);
      35             :         }
      36             : 
      37           0 :         if (destinations.count(dest)) {
      38           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + address);
      39             :         }
      40           0 :         destinations.insert(dest);
      41             : 
      42           0 :         CAmount amount = AmountFromValue(address_amounts[i++]);
      43             : 
      44           0 :         bool subtract_fee = false;
      45           0 :         for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); idx++) {
      46           0 :             const UniValue& addr = subtract_fee_outputs[idx];
      47           0 :             if (addr.get_str() == address) {
      48           0 :                 subtract_fee = true;
      49           0 :             }
      50           0 :         }
      51             : 
      52           0 :         CRecipient recipient = {dest, amount, subtract_fee};
      53           0 :         recipients.push_back(recipient);
      54           0 :     }
      55           0 : }
      56             : 
      57           0 : static void InterpretFeeEstimationInstructions(const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate, UniValue& options)
      58             : {
      59           0 :     if (options.exists("conf_target") || options.exists("estimate_mode")) {
      60           0 :         if (!conf_target.isNull() || !estimate_mode.isNull()) {
      61           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Pass conf_target and estimate_mode either as arguments or in the options object, but not both");
      62             :         }
      63           0 :     } else {
      64           0 :         options.pushKV("conf_target", conf_target);
      65           0 :         options.pushKV("estimate_mode", estimate_mode);
      66             :     }
      67           0 :     if (options.exists("fee_rate")) {
      68           0 :         if (!fee_rate.isNull()) {
      69           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Pass the fee_rate either as an argument, or in the options object, but not both");
      70             :         }
      71           0 :     } else {
      72           0 :         options.pushKV("fee_rate", fee_rate);
      73             :     }
      74         173 :     if (!options["conf_target"].isNull() && (options["estimate_mode"].isNull() || (options["estimate_mode"].get_str() == "unset"))) {
      75           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Specify estimate_mode");
      76             :     }
      77           0 : }
      78             : 
      79           0 : static UniValue FinishTransaction(const std::shared_ptr<CWallet> pwallet, const UniValue& options, const CMutableTransaction& rawTx)
      80             : {
      81             :     // Make a blank psbt
      82           0 :     PartiallySignedTransaction psbtx(rawTx);
      83             : 
      84             :     // First fill transaction with our data without signing,
      85             :     // so external signers are not asked to sign more than once.
      86             :     bool complete;
      87           0 :     pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true);
      88           0 :     const TransactionError err{pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/true, /*bip32derivs=*/false)};
      89           0 :     if (err != TransactionError::OK) {
      90           0 :         throw JSONRPCTransactionError(err);
      91         173 :     }
      92             : 
      93           0 :     CMutableTransaction mtx;
      94           0 :     complete = FinalizeAndExtractPSBT(psbtx, mtx);
      95             : 
      96           0 :     UniValue result(UniValue::VOBJ);
      97             : 
      98           0 :     const bool psbt_opt_in{options.exists("psbt") && options["psbt"].get_bool()};
      99         173 :     bool add_to_wallet{options.exists("add_to_wallet") ? options["add_to_wallet"].get_bool() : true};
     100           0 :     if (psbt_opt_in || !complete || !add_to_wallet) {
     101             :         // Serialize the PSBT
     102           0 :         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
     103           0 :         ssTx << psbtx;
     104           0 :         result.pushKV("psbt", EncodeBase64(ssTx.str()));
     105           0 :     }
     106             : 
     107           0 :     if (complete) {
     108           0 :         std::string hex{EncodeHexTx(CTransaction(mtx))};
     109           0 :         CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
     110           0 :         result.pushKV("txid", tx->GetHash().GetHex());
     111           0 :         if (add_to_wallet && !psbt_opt_in) {
     112           0 :             pwallet->CommitTransaction(tx, {}, /*orderForm=*/{});
     113           0 :         } else {
     114           0 :             result.pushKV("hex", hex);
     115             :         }
     116           0 :     }
     117           0 :     result.pushKV("complete", complete);
     118             : 
     119           0 :     return result;
     120           0 : }
     121             : 
     122           0 : static void PreventOutdatedOptions(const UniValue& options)
     123             : {
     124           0 :     if (options.exists("feeRate")) {
     125           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Use fee_rate (" + CURRENCY_ATOM + "/vB) instead of feeRate");
     126             :     }
     127           0 :     if (options.exists("changeAddress")) {
     128           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_address instead of changeAddress");
     129             :     }
     130           0 :     if (options.exists("changePosition")) {
     131           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_position instead of changePosition");
     132             :     }
     133           0 :     if (options.exists("includeWatching")) {
     134           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Use include_watching instead of includeWatching");
     135             :     }
     136           0 :     if (options.exists("lockUnspents")) {
     137           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Use lock_unspents instead of lockUnspents");
     138             :     }
     139           0 :     if (options.exists("subtractFeeFromOutputs")) {
     140           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Use subtract_fee_from_outputs instead of subtractFeeFromOutputs");
     141             :     }
     142           0 : }
     143             : 
     144           0 : UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value, bool verbose)
     145             : {
     146           0 :     EnsureWalletIsUnlocked(wallet);
     147             : 
     148             :     // This function is only used by sendtoaddress and sendmany.
     149             :     // This should always try to sign, if we don't have private keys, don't try to do anything here.
     150           0 :     if (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
     151           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
     152             :     }
     153             : 
     154             :     // Shuffle recipient list
     155           0 :     std::shuffle(recipients.begin(), recipients.end(), FastRandomContext());
     156             : 
     157             :     // Send
     158           0 :     constexpr int RANDOM_CHANGE_POSITION = -1;
     159           0 :     auto res = CreateTransaction(wallet, recipients, RANDOM_CHANGE_POSITION, coin_control, true);
     160           0 :     if (!res) {
     161           0 :         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, util::ErrorString(res).original);
     162             :     }
     163         173 :     const CTransactionRef& tx = res->tx;
     164         173 :     wallet.CommitTransaction(tx, std::move(map_value), /*orderForm=*/{});
     165         173 :     if (verbose) {
     166         173 :         UniValue entry(UniValue::VOBJ);
     167         173 :         entry.pushKV("txid", tx->GetHash().GetHex());
     168         173 :         entry.pushKV("fee_reason", StringForFeeReason(res->fee_calc.reason));
     169         173 :         return entry;
     170         173 :     }
     171           0 :     return tx->GetHash().GetHex();
     172           0 : }
     173             : 
     174             : 
     175             : /**
     176             :  * Update coin control with fee estimation based on the given parameters
     177             :  *
     178             :  * @param[in]     wallet            Wallet reference
     179             :  * @param[in,out] cc                Coin control to be updated
     180             :  * @param[in]     conf_target       UniValue integer; confirmation target in blocks, values between 1 and 1008 are valid per policy/fees.h;
     181             :  * @param[in]     estimate_mode     UniValue string; fee estimation mode, valid values are "unset", "economical" or "conservative";
     182             :  * @param[in]     fee_rate          UniValue real; fee rate in sat/vB;
     183             :  *                                      if present, both conf_target and estimate_mode must either be null, or "unset"
     184             :  * @param[in]     override_min_fee  bool; whether to set fOverrideFeeRate to true to disable minimum fee rate checks and instead
     185             :  *                                      verify only that fee_rate is greater than 0
     186             :  * @throws a JSONRPCError if conf_target, estimate_mode, or fee_rate contain invalid values or are in conflict
     187             :  */
     188           0 : static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate, bool override_min_fee)
     189             : {
     190           0 :     if (!fee_rate.isNull()) {
     191           0 :         if (!conf_target.isNull()) {
     192           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
     193             :         }
     194           0 :         if (!estimate_mode.isNull() && estimate_mode.get_str() != "unset") {
     195           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and fee_rate");
     196             :         }
     197             :         // Fee rates in sat/vB cannot represent more than 3 significant digits.
     198           0 :         cc.m_feerate = CFeeRate{AmountFromValue(fee_rate, /*decimals=*/3)};
     199           0 :         if (override_min_fee) cc.fOverrideFeeRate = true;
     200             :         // Default RBF to true for explicit fee_rate, if unset.
     201           0 :         if (!cc.m_signal_bip125_rbf) cc.m_signal_bip125_rbf = true;
     202           0 :         return;
     203             :     }
     204           0 :     if (!estimate_mode.isNull() && !FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) {
     205           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage());
     206             :     }
     207           0 :     if (!conf_target.isNull()) {
     208           0 :         cc.m_confirm_target = ParseConfirmTarget(conf_target, wallet.chain().estimateMaxBlocks());
     209           0 :     }
     210           0 : }
     211             : 
     212           0 : RPCHelpMan sendtoaddress()
     213             : {
     214           0 :     return RPCHelpMan{"sendtoaddress",
     215           0 :                 "\nSend an amount to a given address." +
     216             :         HELP_REQUIRING_PASSPHRASE,
     217           0 :                 {
     218           0 :                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to send to."},
     219           0 :                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
     220           0 :                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A comment used to store what the transaction is for.\n"
     221             :                                          "This is not part of the transaction, just kept in your wallet."},
     222           0 :                     {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A comment to store the name of the person or organization\n"
     223             :                                          "to which you're sending the transaction. This is not part of the \n"
     224             :                                          "transaction, just kept in your wallet."},
     225           0 :                     {"subtractfeefromamount", RPCArg::Type::BOOL, RPCArg::Default{false}, "The fee will be deducted from the amount being sent.\n"
     226             :                                          "The recipient will receive less bitcoins than you enter in the amount field."},
     227           0 :                     {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Signal that this transaction can be replaced by a transaction (BIP 125)"},
     228           0 :                     {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
     229           0 :                     {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
     230           0 :                      "\"" + FeeModes("\"\n\"") + "\""},
     231           0 :                     {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
     232             :                                          "dirty if they have previously been used in a transaction. If true, this also activates avoidpartialspends, grouping outputs by their addresses."},
     233           0 :                     {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
     234           0 :                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra information about the transaction."},
     235             :                 },
     236           0 :                 {
     237           0 :                     RPCResult{"if verbose is not set or set to false",
     238           0 :                         RPCResult::Type::STR_HEX, "txid", "The transaction id."
     239             :                     },
     240           0 :                     RPCResult{"if verbose is set to true",
     241           0 :                         RPCResult::Type::OBJ, "", "",
     242           0 :                         {
     243           0 :                             {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
     244           0 :                             {RPCResult::Type::STR, "fee_reason", "The transaction fee reason."}
     245             :                         },
     246             :                     },
     247             :                 },
     248           0 :                 RPCExamples{
     249             :                     "\nSend 0.1 BTC\n"
     250           0 :                     + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1") +
     251             :                     "\nSend 0.1 BTC with a confirmation target of 6 blocks in economical fee estimate mode using positional arguments\n"
     252           0 :                     + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"sean's outpost\" false true 6 economical") +
     253           0 :                     "\nSend 0.1 BTC with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB, subtract fee from amount, BIP125-replaceable, using positional arguments\n"
     254           0 :                     + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"drinks\" \"room77\" true true null \"unset\" null 1.1") +
     255             :                     "\nSend 0.2 BTC with a confirmation target of 6 blocks in economical fee estimate mode using named arguments\n"
     256           0 :                     + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.2 conf_target=6 estimate_mode=\"economical\"") +
     257           0 :                     "\nSend 0.5 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n"
     258           0 :                     + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25")
     259           0 :                     + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25 subtractfeefromamount=false replaceable=true avoid_reuse=true comment=\"2 pizzas\" comment_to=\"jeremy\" verbose=true")
     260             :                 },
     261           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     262             : {
     263           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     264           0 :     if (!pwallet) return UniValue::VNULL;
     265             : 
     266             :     // Make sure the results are valid at least up to the most recent block
     267             :     // the user could have gotten from another RPC command prior to now
     268           0 :     pwallet->BlockUntilSyncedToCurrentChain();
     269             : 
     270         173 :     LOCK(pwallet->cs_wallet);
     271             : 
     272             :     // Wallet comments
     273           0 :     mapValue_t mapValue;
     274           0 :     if (!request.params[2].isNull() && !request.params[2].get_str().empty())
     275           0 :         mapValue["comment"] = request.params[2].get_str();
     276           0 :     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
     277           0 :         mapValue["to"] = request.params[3].get_str();
     278             : 
     279           0 :     bool fSubtractFeeFromAmount = false;
     280           0 :     if (!request.params[4].isNull()) {
     281           0 :         fSubtractFeeFromAmount = request.params[4].get_bool();
     282           0 :     }
     283             : 
     284           0 :     CCoinControl coin_control;
     285           0 :     if (!request.params[5].isNull()) {
     286           0 :         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
     287           0 :     }
     288             : 
     289           0 :     coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(*pwallet, request.params[8]);
     290             :     // We also enable partial spend avoidance if reuse avoidance is set.
     291           0 :     coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
     292             : 
     293           0 :     SetFeeEstimateMode(*pwallet, coin_control, /*conf_target=*/request.params[6], /*estimate_mode=*/request.params[7], /*fee_rate=*/request.params[9], /*override_min_fee=*/false);
     294             : 
     295           0 :     EnsureWalletIsUnlocked(*pwallet);
     296             : 
     297           0 :     UniValue address_amounts(UniValue::VOBJ);
     298           0 :     const std::string address = request.params[0].get_str();
     299           0 :     address_amounts.pushKV(address, request.params[1]);
     300           0 :     UniValue subtractFeeFromAmount(UniValue::VARR);
     301           0 :     if (fSubtractFeeFromAmount) {
     302           0 :         subtractFeeFromAmount.push_back(address);
     303           0 :     }
     304             : 
     305           0 :     std::vector<CRecipient> recipients;
     306           0 :     ParseRecipients(address_amounts, subtractFeeFromAmount, recipients);
     307           0 :     const bool verbose{request.params[10].isNull() ? false : request.params[10].get_bool()};
     308             : 
     309           0 :     return SendMoney(*pwallet, coin_control, recipients, mapValue, verbose);
     310           0 : },
     311             :     };
     312           0 : }
     313             : 
     314           0 : RPCHelpMan sendmany()
     315             : {
     316           0 :     return RPCHelpMan{"sendmany",
     317           0 :         "Send multiple times. Amounts are double-precision floating point numbers." +
     318             :         HELP_REQUIRING_PASSPHRASE,
     319           0 :                 {
     320           0 :                     {"dummy", RPCArg::Type::STR, RPCArg::Default{"\"\""}, "Must be set to \"\" for backwards compatibility.",
     321           0 :                      RPCArgOptions{
     322           0 :                          .oneline_description = "\"\"",
     323             :                      }},
     324           0 :                     {"amounts", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::NO, "The addresses and amounts",
     325           0 :                         {
     326           0 :                             {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
     327             :                         },
     328             :                     },
     329           0 :                     {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Ignored dummy value"},
     330           0 :                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A comment"},
     331           0 :                     {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The addresses.\n"
     332             :                                        "The fee will be equally deducted from the amount of each selected address.\n"
     333             :                                        "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
     334             :                                        "If no addresses are specified here, the sender pays the fee.",
     335           0 :                         {
     336           0 :                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
     337             :                         },
     338             :                     },
     339           0 :                     {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Signal that this transaction can be replaced by a transaction (BIP 125)"},
     340           0 :                     {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
     341           0 :                     {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
     342           0 :                      "\"" + FeeModes("\"\n\"") + "\""},
     343           0 :                     {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
     344           0 :                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra information about the transaction."},
     345             :                 },
     346           0 :                 {
     347           0 :                     RPCResult{"if verbose is not set or set to false",
     348           0 :                         RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
     349             :                 "the number of addresses."
     350             :                     },
     351           0 :                     RPCResult{"if verbose is set to true",
     352           0 :                         RPCResult::Type::OBJ, "", "",
     353           0 :                         {
     354           0 :                             {RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
     355             :                 "the number of addresses."},
     356           0 :                             {RPCResult::Type::STR, "fee_reason", "The transaction fee reason."}
     357             :                         },
     358             :                     },
     359             :                 },
     360           0 :                 RPCExamples{
     361             :             "\nSend two amounts to two different addresses:\n"
     362           0 :             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\"") +
     363             :             "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
     364           0 :             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 6 \"testing\"") +
     365             :             "\nSend two amounts to two different addresses, subtract fee from amount:\n"
     366           0 :             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 1 \"\" \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
     367             :             "\nAs a JSON-RPC call\n"
     368           0 :             + HelpExampleRpc("sendmany", "\"\", {\"" + EXAMPLE_ADDRESS[0] + "\":0.01,\"" + EXAMPLE_ADDRESS[1] + "\":0.02}, 6, \"testing\"")
     369             :                 },
     370           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     371             : {
     372           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     373           0 :     if (!pwallet) return UniValue::VNULL;
     374             : 
     375             :     // Make sure the results are valid at least up to the most recent block
     376             :     // the user could have gotten from another RPC command prior to now
     377           0 :     pwallet->BlockUntilSyncedToCurrentChain();
     378             : 
     379           0 :     LOCK(pwallet->cs_wallet);
     380             : 
     381           0 :     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
     382           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
     383             :     }
     384           0 :     UniValue sendTo = request.params[1].get_obj();
     385             : 
     386           0 :     mapValue_t mapValue;
     387           0 :     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
     388           0 :         mapValue["comment"] = request.params[3].get_str();
     389             : 
     390           0 :     UniValue subtractFeeFromAmount(UniValue::VARR);
     391           0 :     if (!request.params[4].isNull())
     392           0 :         subtractFeeFromAmount = request.params[4].get_array();
     393             : 
     394           0 :     CCoinControl coin_control;
     395           0 :     if (!request.params[5].isNull()) {
     396           0 :         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
     397           0 :     }
     398             : 
     399           0 :     SetFeeEstimateMode(*pwallet, coin_control, /*conf_target=*/request.params[6], /*estimate_mode=*/request.params[7], /*fee_rate=*/request.params[8], /*override_min_fee=*/false);
     400             : 
     401           0 :     std::vector<CRecipient> recipients;
     402           0 :     ParseRecipients(sendTo, subtractFeeFromAmount, recipients);
     403           0 :     const bool verbose{request.params[9].isNull() ? false : request.params[9].get_bool()};
     404             : 
     405           0 :     return SendMoney(*pwallet, coin_control, recipients, std::move(mapValue), verbose);
     406           0 : },
     407             :     };
     408           0 : }
     409             : 
     410           0 : RPCHelpMan settxfee()
     411             : {
     412           0 :     return RPCHelpMan{"settxfee",
     413           0 :                 "\nSet the transaction fee rate in " + CURRENCY_UNIT + "/kvB for this wallet. Overrides the global -paytxfee command line parameter.\n"
     414             :                 "Can be deactivated by passing 0 as the fee. In that case automatic fee selection will be used by default.\n",
     415           0 :                 {
     416           0 :                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee rate in " + CURRENCY_UNIT + "/kvB"},
     417             :                 },
     418           0 :                 RPCResult{
     419           0 :                     RPCResult::Type::BOOL, "", "Returns true if successful"
     420             :                 },
     421           0 :                 RPCExamples{
     422           0 :                     HelpExampleCli("settxfee", "0.00001")
     423           0 :             + HelpExampleRpc("settxfee", "0.00001")
     424             :                 },
     425           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     426             : {
     427           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     428           0 :     if (!pwallet) return UniValue::VNULL;
     429             : 
     430           0 :     LOCK(pwallet->cs_wallet);
     431             : 
     432           0 :     CAmount nAmount = AmountFromValue(request.params[0]);
     433           0 :     CFeeRate tx_fee_rate(nAmount, 1000);
     434           0 :     CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
     435           0 :     if (tx_fee_rate == CFeeRate(0)) {
     436             :         // automatic selection
     437           0 :     } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
     438           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
     439           0 :     } else if (tx_fee_rate < pwallet->m_min_fee) {
     440           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
     441           0 :     } else if (tx_fee_rate > max_tx_fee_rate) {
     442           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be more than wallet max tx fee (%s)", max_tx_fee_rate.ToString()));
     443             :     }
     444             : 
     445           0 :     pwallet->m_pay_tx_fee = tx_fee_rate;
     446           0 :     return true;
     447           0 : },
     448             :     };
     449           0 : }
     450             : 
     451             : 
     452             : // Only includes key documentation where the key is snake_case in all RPC methods. MixedCase keys can be added later.
     453           0 : static std::vector<RPCArg> FundTxDoc(bool solving_data = true)
     454             : {
     455           0 :     std::vector<RPCArg> args = {
     456           0 :         {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks", RPCArgOptions{.also_positional = true}},
     457           0 :         {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
     458           0 :          "\"" + FeeModes("\"\n\"") + "\"", RPCArgOptions{.also_positional = true}},
     459           0 :         {
     460           0 :             "replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125-replaceable.\n"
     461             :             "Allows this transaction to be replaced by a transaction with higher fees"
     462             :         },
     463             :     };
     464           0 :     if (solving_data) {
     465           0 :         args.push_back({"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
     466             :         "Used for fee estimation during coin selection.",
     467           0 :             {
     468           0 :                 {
     469           0 :                     "pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Public keys involved in this transaction.",
     470           0 :                     {
     471           0 :                         {"pubkey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A public key"},
     472             :                     }
     473             :                 },
     474           0 :                 {
     475           0 :                     "scripts", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Scripts involved in this transaction.",
     476           0 :                     {
     477           0 :                         {"script", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A script"},
     478             :                     }
     479             :                 },
     480           0 :                 {
     481           0 :                     "descriptors", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Descriptors that provide solving data for this transaction.",
     482           0 :                     {
     483           0 :                         {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A descriptor"},
     484             :                     }
     485             :                 },
     486             :             }
     487             :         });
     488           0 :     }
     489           0 :     return args;
     490           0 : }
     491             : 
     492           0 : void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, const UniValue& options, CCoinControl& coinControl, bool override_min_fee)
     493             : {
     494             :     // Make sure the results are valid at least up to the most recent block
     495             :     // the user could have gotten from another RPC command prior to now
     496           0 :     wallet.BlockUntilSyncedToCurrentChain();
     497             : 
     498           0 :     change_position = -1;
     499           0 :     bool lockUnspents = false;
     500           0 :     UniValue subtractFeeFromOutputs;
     501           0 :     std::set<int> setSubtractFeeFromOutputs;
     502             : 
     503           0 :     if (!options.isNull()) {
     504           0 :       if (options.type() == UniValue::VBOOL) {
     505             :         // backward compatibility bool only fallback
     506           0 :         coinControl.fAllowWatchOnly = options.get_bool();
     507           0 :       }
     508             :       else {
     509           0 :         RPCTypeCheckObj(options,
     510           0 :             {
     511           0 :                 {"add_inputs", UniValueType(UniValue::VBOOL)},
     512           0 :                 {"include_unsafe", UniValueType(UniValue::VBOOL)},
     513           0 :                 {"add_to_wallet", UniValueType(UniValue::VBOOL)},
     514           0 :                 {"changeAddress", UniValueType(UniValue::VSTR)},
     515           0 :                 {"change_address", UniValueType(UniValue::VSTR)},
     516           0 :                 {"changePosition", UniValueType(UniValue::VNUM)},
     517           0 :                 {"change_position", UniValueType(UniValue::VNUM)},
     518           0 :                 {"change_type", UniValueType(UniValue::VSTR)},
     519           0 :                 {"includeWatching", UniValueType(UniValue::VBOOL)},
     520           0 :                 {"include_watching", UniValueType(UniValue::VBOOL)},
     521           0 :                 {"inputs", UniValueType(UniValue::VARR)},
     522           0 :                 {"lockUnspents", UniValueType(UniValue::VBOOL)},
     523           0 :                 {"lock_unspents", UniValueType(UniValue::VBOOL)},
     524           0 :                 {"locktime", UniValueType(UniValue::VNUM)},
     525           0 :                 {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
     526           0 :                 {"feeRate", UniValueType()}, // will be checked by AmountFromValue() below
     527           0 :                 {"psbt", UniValueType(UniValue::VBOOL)},
     528           0 :                 {"solving_data", UniValueType(UniValue::VOBJ)},
     529           0 :                 {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
     530           0 :                 {"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
     531           0 :                 {"replaceable", UniValueType(UniValue::VBOOL)},
     532           0 :                 {"conf_target", UniValueType(UniValue::VNUM)},
     533           0 :                 {"estimate_mode", UniValueType(UniValue::VSTR)},
     534           0 :                 {"minconf", UniValueType(UniValue::VNUM)},
     535           0 :                 {"maxconf", UniValueType(UniValue::VNUM)},
     536           0 :                 {"input_weights", UniValueType(UniValue::VARR)},
     537             :             },
     538             :             true, true);
     539             : 
     540           0 :         if (options.exists("add_inputs")) {
     541           0 :             coinControl.m_allow_other_inputs = options["add_inputs"].get_bool();
     542           0 :         }
     543             : 
     544           0 :         if (options.exists("changeAddress") || options.exists("change_address")) {
     545           0 :             const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str();
     546           0 :             CTxDestination dest = DecodeDestination(change_address_str);
     547             : 
     548           0 :             if (!IsValidDestination(dest)) {
     549           0 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");
     550             :             }
     551             : 
     552           0 :             coinControl.destChange = dest;
     553           0 :         }
     554             : 
     555           0 :         if (options.exists("changePosition") || options.exists("change_position")) {
     556           0 :             change_position = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).getInt<int>();
     557           0 :         }
     558             : 
     559           0 :         if (options.exists("change_type")) {
     560           0 :             if (options.exists("changeAddress") || options.exists("change_address")) {
     561           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");
     562             :             }
     563           0 :             if (std::optional<OutputType> parsed = ParseOutputType(options["change_type"].get_str())) {
     564           0 :                 coinControl.m_change_type.emplace(parsed.value());
     565           0 :             } else {
     566           0 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
     567             :             }
     568           0 :         }
     569             : 
     570           0 :         const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"];
     571           0 :         coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, wallet);
     572             : 
     573           0 :         if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
     574           0 :             lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
     575           0 :         }
     576             : 
     577           0 :         if (options.exists("include_unsafe")) {
     578           0 :             coinControl.m_include_unsafe_inputs = options["include_unsafe"].get_bool();
     579           0 :         }
     580             : 
     581           0 :         if (options.exists("feeRate")) {
     582           0 :             if (options.exists("fee_rate")) {
     583           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both fee_rate (" + CURRENCY_ATOM + "/vB) and feeRate (" + CURRENCY_UNIT + "/kvB)");
     584             :             }
     585           0 :             if (options.exists("conf_target")) {
     586           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
     587             :             }
     588           0 :             if (options.exists("estimate_mode")) {
     589           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
     590             :             }
     591           0 :             coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
     592           0 :             coinControl.fOverrideFeeRate = true;
     593           0 :         }
     594             : 
     595           0 :         if (options.exists("subtractFeeFromOutputs") || options.exists("subtract_fee_from_outputs") )
     596           0 :             subtractFeeFromOutputs = (options.exists("subtract_fee_from_outputs") ? options["subtract_fee_from_outputs"] : options["subtractFeeFromOutputs"]).get_array();
     597             : 
     598           0 :         if (options.exists("replaceable")) {
     599           0 :             coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
     600           0 :         }
     601             : 
     602           0 :         if (options.exists("minconf")) {
     603           0 :             coinControl.m_min_depth = options["minconf"].getInt<int>();
     604             : 
     605           0 :             if (coinControl.m_min_depth < 0) {
     606           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative minconf");
     607             :             }
     608           0 :         }
     609             : 
     610           0 :         if (options.exists("maxconf")) {
     611           0 :             coinControl.m_max_depth = options["maxconf"].getInt<int>();
     612             : 
     613           0 :             if (coinControl.m_max_depth < coinControl.m_min_depth) {
     614           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coinControl.m_max_depth, coinControl.m_min_depth));
     615             :             }
     616           0 :         }
     617           0 :         SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee);
     618           0 :       }
     619           0 :     } else {
     620             :         // if options is null and not a bool
     621           0 :         coinControl.fAllowWatchOnly = ParseIncludeWatchonly(NullUniValue, wallet);
     622             :     }
     623             : 
     624           0 :     if (options.exists("solving_data")) {
     625           0 :         const UniValue solving_data = options["solving_data"].get_obj();
     626           0 :         if (solving_data.exists("pubkeys")) {
     627           0 :             for (const UniValue& pk_univ : solving_data["pubkeys"].get_array().getValues()) {
     628           0 :                 const std::string& pk_str = pk_univ.get_str();
     629           0 :                 if (!IsHex(pk_str)) {
     630           0 :                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not hex", pk_str));
     631             :                 }
     632           0 :                 const std::vector<unsigned char> data(ParseHex(pk_str));
     633           0 :                 const CPubKey pubkey(data.begin(), data.end());
     634           0 :                 if (!pubkey.IsFullyValid()) {
     635           0 :                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not a valid public key", pk_str));
     636             :                 }
     637           0 :                 coinControl.m_external_provider.pubkeys.emplace(pubkey.GetID(), pubkey);
     638             :                 // Add witness script for pubkeys
     639           0 :                 const CScript wit_script = GetScriptForDestination(WitnessV0KeyHash(pubkey));
     640           0 :                 coinControl.m_external_provider.scripts.emplace(CScriptID(wit_script), wit_script);
     641           0 :             }
     642           0 :         }
     643             : 
     644           0 :         if (solving_data.exists("scripts")) {
     645           0 :             for (const UniValue& script_univ : solving_data["scripts"].get_array().getValues()) {
     646           0 :                 const std::string& script_str = script_univ.get_str();
     647           0 :                 if (!IsHex(script_str)) {
     648           0 :                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not hex", script_str));
     649             :                 }
     650           0 :                 std::vector<unsigned char> script_data(ParseHex(script_str));
     651           0 :                 const CScript script(script_data.begin(), script_data.end());
     652           0 :                 coinControl.m_external_provider.scripts.emplace(CScriptID(script), script);
     653           0 :             }
     654           0 :         }
     655             : 
     656           0 :         if (solving_data.exists("descriptors")) {
     657           0 :             for (const UniValue& desc_univ : solving_data["descriptors"].get_array().getValues()) {
     658           0 :                 const std::string& desc_str  = desc_univ.get_str();
     659           0 :                 FlatSigningProvider desc_out;
     660           0 :                 std::string error;
     661           0 :                 std::vector<CScript> scripts_temp;
     662           0 :                 std::unique_ptr<Descriptor> desc = Parse(desc_str, desc_out, error, true);
     663           0 :                 if (!desc) {
     664           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unable to parse descriptor '%s': %s", desc_str, error));
     665             :                 }
     666           0 :                 desc->Expand(0, desc_out, scripts_temp, desc_out);
     667           0 :                 coinControl.m_external_provider.Merge(std::move(desc_out));
     668           0 :             }
     669           0 :         }
     670           0 :     }
     671             : 
     672           0 :     if (options.exists("input_weights")) {
     673           0 :         for (const UniValue& input : options["input_weights"].get_array().getValues()) {
     674           0 :             uint256 txid = ParseHashO(input, "txid");
     675             : 
     676           0 :             const UniValue& vout_v = input.find_value("vout");
     677           0 :             if (!vout_v.isNum()) {
     678           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
     679             :             }
     680           0 :             int vout = vout_v.getInt<int>();
     681           0 :             if (vout < 0) {
     682           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
     683             :             }
     684             : 
     685           0 :             const UniValue& weight_v = input.find_value("weight");
     686           0 :             if (!weight_v.isNum()) {
     687           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing weight key");
     688             :             }
     689           0 :             int64_t weight = weight_v.getInt<int64_t>();
     690           0 :             const int64_t min_input_weight = GetTransactionInputWeight(CTxIn());
     691           0 :             CHECK_NONFATAL(min_input_weight == 165);
     692           0 :             if (weight < min_input_weight) {
     693           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, weight cannot be less than 165 (41 bytes (size of outpoint + sequence + empty scriptSig) * 4 (witness scaling factor)) + 1 (empty witness)");
     694             :             }
     695           0 :             if (weight > MAX_STANDARD_TX_WEIGHT) {
     696           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, weight cannot be greater than the maximum standard tx weight of %d", MAX_STANDARD_TX_WEIGHT));
     697             :             }
     698             : 
     699           0 :             coinControl.SetInputWeight(COutPoint(txid, vout), weight);
     700             :         }
     701           0 :     }
     702             : 
     703           0 :     if (tx.vout.size() == 0)
     704           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
     705             : 
     706           0 :     if (change_position != -1 && (change_position < 0 || (unsigned int)change_position > tx.vout.size()))
     707           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
     708             : 
     709           0 :     for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
     710           0 :         int pos = subtractFeeFromOutputs[idx].getInt<int>();
     711           0 :         if (setSubtractFeeFromOutputs.count(pos))
     712           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
     713           0 :         if (pos < 0)
     714           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
     715           0 :         if (pos >= int(tx.vout.size()))
     716           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
     717           0 :         setSubtractFeeFromOutputs.insert(pos);
     718           0 :     }
     719             : 
     720           0 :     bilingual_str error;
     721             : 
     722           0 :     if (!FundTransaction(wallet, tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
     723           0 :         throw JSONRPCError(RPC_WALLET_ERROR, error.original);
     724             :     }
     725           0 : }
     726             : 
     727           0 : static void SetOptionsInputWeights(const UniValue& inputs, UniValue& options)
     728             : {
     729           0 :     if (options.exists("input_weights")) {
     730           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Input weights should be specified in inputs rather than in options.");
     731             :     }
     732           0 :     if (inputs.size() == 0) {
     733           0 :         return;
     734             :     }
     735           0 :     UniValue weights(UniValue::VARR);
     736           0 :     for (const UniValue& input : inputs.getValues()) {
     737           0 :         if (input.exists("weight")) {
     738           0 :             weights.push_back(input);
     739           0 :         }
     740             :     }
     741           0 :     options.pushKV("input_weights", weights);
     742           0 : }
     743             : 
     744           0 : RPCHelpMan fundrawtransaction()
     745             : {
     746           0 :     return RPCHelpMan{"fundrawtransaction",
     747           0 :                 "\nIf the transaction has no inputs, they will be automatically selected to meet its out value.\n"
     748             :                 "It will add at most one change output to the outputs.\n"
     749             :                 "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
     750             :                 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
     751             :                 "The inputs added will not be signed, use signrawtransactionwithkey\n"
     752             :                 "or signrawtransactionwithwallet for that.\n"
     753             :                 "All existing inputs must either have their previous output transaction be in the wallet\n"
     754             :                 "or be in the UTXO set. Solving data must be provided for non-wallet inputs.\n"
     755             :                 "Note that all inputs selected must be of standard form and P2SH scripts must be\n"
     756             :                 "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
     757             :                 "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
     758             :                 "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
     759           0 :                 {
     760           0 :                     {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
     761           0 :                     {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "For backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
     762           0 :                         Cat<std::vector<RPCArg>>(
     763           0 :                         {
     764           0 :                             {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
     765           0 :                             {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
     766             :                                                           "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
     767             :                                                           "If that happens, you will need to fund the transaction with different inputs and republish it."},
     768           0 :                             {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."},
     769           0 :                             {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."},
     770           0 :                             {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
     771           0 :                             {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
     772           0 :                             {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
     773           0 :                             {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
     774             :                                                           "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
     775             :                                                           "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
     776           0 :                             {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
     777           0 :                             {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
     778           0 :                             {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
     779           0 :                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The integers.\n"
     780             :                                                           "The fee will be equally deducted from the amount of each specified output.\n"
     781             :                                                           "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
     782             :                                                           "If no outputs are specified here, the sender pays the fee.",
     783           0 :                                 {
     784           0 :                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
     785             :                                 },
     786             :                             },
     787           0 :                             {"input_weights", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Inputs and their corresponding weights",
     788           0 :                                 {
     789           0 :                                     {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
     790           0 :                                         {
     791           0 :                                             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
     792           0 :                                             {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"},
     793           0 :                                             {"weight", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum weight for this input, "
     794             :                                                 "including the weight of the outpoint and sequence number. "
     795             :                                                 "Note that serialized signature sizes are not guaranteed to be consistent, "
     796             :                                                 "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures."
     797             :                                                 "Remember to convert serialized sizes to weight units when necessary."},
     798             :                                         },
     799             :                                     },
     800             :                                 },
     801             :                              },
     802             :                         },
     803           0 :                         FundTxDoc()),
     804           0 :                         RPCArgOptions{
     805             :                             .skip_type_check = true,
     806           0 :                             .oneline_description = "options",
     807             :                         }},
     808           0 :                     {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n"
     809             :                         "If iswitness is not present, heuristic tests will be used in decoding.\n"
     810             :                         "If true, only witness deserialization will be tried.\n"
     811             :                         "If false, only non-witness deserialization will be tried.\n"
     812             :                         "This boolean should reflect whether the transaction has inputs\n"
     813             :                         "(e.g. fully valid, or on-chain transactions), if known by the caller."
     814             :                     },
     815             :                 },
     816           0 :                 RPCResult{
     817           0 :                     RPCResult::Type::OBJ, "", "",
     818           0 :                     {
     819           0 :                         {RPCResult::Type::STR_HEX, "hex", "The resulting raw transaction (hex-encoded string)"},
     820           0 :                         {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
     821           0 :                         {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
     822             :                     }
     823             :                                 },
     824           0 :                                 RPCExamples{
     825             :                             "\nCreate a transaction with no inputs\n"
     826           0 :                             + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
     827             :                             "\nAdd sufficient unsigned inputs to meet the output value\n"
     828           0 :                             + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
     829             :                             "\nSign the transaction\n"
     830           0 :                             + HelpExampleCli("signrawtransactionwithwallet", "\"fundedtransactionhex\"") +
     831             :                             "\nSend the transaction\n"
     832           0 :                             + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
     833             :                                 },
     834           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     835             : {
     836           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
     837           0 :     if (!pwallet) return UniValue::VNULL;
     838             : 
     839             :     // parse hex string from parameter
     840           0 :     CMutableTransaction tx;
     841           0 :     bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
     842           0 :     bool try_no_witness = request.params[2].isNull() ? true : !request.params[2].get_bool();
     843           0 :     if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
     844           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
     845             :     }
     846             : 
     847             :     CAmount fee;
     848             :     int change_position;
     849           0 :     CCoinControl coin_control;
     850             :     // Automatically select (additional) coins. Can be overridden by options.add_inputs.
     851           0 :     coin_control.m_allow_other_inputs = true;
     852           0 :     FundTransaction(*pwallet, tx, fee, change_position, request.params[1], coin_control, /*override_min_fee=*/true);
     853             : 
     854           0 :     UniValue result(UniValue::VOBJ);
     855           0 :     result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
     856           0 :     result.pushKV("fee", ValueFromAmount(fee));
     857           0 :     result.pushKV("changepos", change_position);
     858             : 
     859           0 :     return result;
     860           0 : },
     861             :     };
     862           0 : }
     863             : 
     864           0 : RPCHelpMan signrawtransactionwithwallet()
     865             : {
     866           0 :     return RPCHelpMan{"signrawtransactionwithwallet",
     867             :                 "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
     868             :                 "The second optional argument (may be null) is an array of previous transaction outputs that\n"
     869           0 :                 "this transaction depends on but may not yet be in the block chain." +
     870             :         HELP_REQUIRING_PASSPHRASE,
     871           0 :                 {
     872           0 :                     {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
     873           0 :                     {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The previous dependent transaction outputs",
     874           0 :                         {
     875           0 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
     876           0 :                                 {
     877           0 :                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
     878           0 :                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
     879           0 :                                     {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
     880           0 :                                     {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
     881           0 :                                     {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
     882           0 :                                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"},
     883             :                                 },
     884             :                             },
     885             :                         },
     886             :                     },
     887           0 :                     {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT for Taproot, ALL otherwise"}, "The signature hash type. Must be one of\n"
     888             :             "       \"DEFAULT\"\n"
     889             :             "       \"ALL\"\n"
     890             :             "       \"NONE\"\n"
     891             :             "       \"SINGLE\"\n"
     892             :             "       \"ALL|ANYONECANPAY\"\n"
     893             :             "       \"NONE|ANYONECANPAY\"\n"
     894             :             "       \"SINGLE|ANYONECANPAY\""},
     895             :                 },
     896           0 :                 RPCResult{
     897           0 :                     RPCResult::Type::OBJ, "", "",
     898           0 :                     {
     899           0 :                         {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"},
     900           0 :                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
     901           0 :                         {RPCResult::Type::ARR, "errors", /*optional=*/true, "Script verification errors (if there are any)",
     902           0 :                         {
     903           0 :                             {RPCResult::Type::OBJ, "", "",
     904           0 :                             {
     905           0 :                                 {RPCResult::Type::STR_HEX, "txid", "The hash of the referenced, previous transaction"},
     906           0 :                                 {RPCResult::Type::NUM, "vout", "The index of the output to spent and used as input"},
     907           0 :                                 {RPCResult::Type::ARR, "witness", "",
     908           0 :                                 {
     909           0 :                                     {RPCResult::Type::STR_HEX, "witness", ""},
     910             :                                 }},
     911           0 :                                 {RPCResult::Type::STR_HEX, "scriptSig", "The hex-encoded signature script"},
     912           0 :                                 {RPCResult::Type::NUM, "sequence", "Script sequence number"},
     913           0 :                                 {RPCResult::Type::STR, "error", "Verification or signing error related to the input"},
     914             :                             }},
     915             :                         }},
     916             :                     }
     917             :                 },
     918           0 :                 RPCExamples{
     919           0 :                     HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
     920           0 :             + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
     921             :                 },
     922           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     923             : {
     924           0 :     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
     925           0 :     if (!pwallet) return UniValue::VNULL;
     926             : 
     927           0 :     CMutableTransaction mtx;
     928           0 :     if (!DecodeHexTx(mtx, request.params[0].get_str())) {
     929           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
     930             :     }
     931             : 
     932             :     // Sign the transaction
     933           0 :     LOCK(pwallet->cs_wallet);
     934           0 :     EnsureWalletIsUnlocked(*pwallet);
     935             : 
     936             :     // Fetch previous transactions (inputs):
     937           0 :     std::map<COutPoint, Coin> coins;
     938           0 :     for (const CTxIn& txin : mtx.vin) {
     939           0 :         coins[txin.prevout]; // Create empty map entry keyed by prevout.
     940             :     }
     941           0 :     pwallet->chain().findCoins(coins);
     942             : 
     943             :     // Parse the prevtxs array
     944           0 :     ParsePrevouts(request.params[1], nullptr, coins);
     945             : 
     946           0 :     int nHashType = ParseSighashString(request.params[2]);
     947             : 
     948             :     // Script verification errors
     949           0 :     std::map<int, bilingual_str> input_errors;
     950             : 
     951           0 :     bool complete = pwallet->SignTransaction(mtx, coins, nHashType, input_errors);
     952           0 :     UniValue result(UniValue::VOBJ);
     953           0 :     SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
     954           0 :     return result;
     955           0 : },
     956             :     };
     957           0 : }
     958             : 
     959             : // Definition of allowed formats of specifying transaction outputs in
     960             : // `bumpfee`, `psbtbumpfee`, `send` and `walletcreatefundedpsbt` RPCs.
     961           0 : static std::vector<RPCArg> OutputsDoc()
     962             : {
     963           0 :     return
     964           0 :     {
     965           0 :         {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
     966           0 :             {
     967           0 :                 {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address,\n"
     968           0 :                          "the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
     969             :             },
     970             :         },
     971           0 :         {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
     972           0 :             {
     973           0 :                 {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
     974             :             },
     975             :         },
     976             :     };
     977           0 : }
     978             : 
     979           0 : static RPCHelpMan bumpfee_helper(std::string method_name)
     980             : {
     981           0 :     const bool want_psbt = method_name == "psbtbumpfee";
     982           0 :     const std::string incremental_fee{CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE).ToString(FeeEstimateMode::SAT_VB)};
     983             : 
     984           0 :     return RPCHelpMan{method_name,
     985             :         "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
     986           0 :         + std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") +
     987             :         "An opt-in RBF transaction with the given txid must be in the wallet.\n"
     988             :         "The command will pay the additional fee by reducing change outputs or adding inputs when necessary.\n"
     989             :         "It may add a new change output if one does not already exist.\n"
     990             :         "All inputs in the original transaction will be included in the replacement transaction.\n"
     991             :         "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
     992             :         "By default, the new fee will be calculated automatically using the estimatesmartfee RPC.\n"
     993             :         "The user can specify a confirmation target for estimatesmartfee.\n"
     994           0 :         "Alternatively, the user can specify a fee rate in " + CURRENCY_ATOM + "/vB for the new transaction.\n"
     995             :         "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
     996             :         "returned by getnetworkinfo) to enter the node's mempool.\n"
     997           0 :         "* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n",
     998           0 :         {
     999           0 :             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
    1000           0 :             {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
    1001           0 :                 {
    1002           0 :                     {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"},
    1003           0 :                     {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"},
    1004           0 :                              "\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n"
    1005           0 :                              "Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n"
    1006           0 :                              "WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"},
    1007           0 :                     {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether the new transaction should still be\n"
    1008             :                              "marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
    1009             :                              "be left unchanged from the original. If false, any input sequence numbers in the\n"
    1010             :                              "original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
    1011             :                              "so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
    1012             :                              "still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
    1013             :                              "are replaceable).\n"},
    1014           0 :                     {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
    1015           0 :                              "\"" + FeeModes("\"\n\"") + "\""},
    1016           0 :                     {"outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The outputs specified as key-value pairs.\n"
    1017             :                              "Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n"
    1018             :                              "At least one output of either type must be specified.\n"
    1019             :                              "Cannot be provided if 'reduce_output' is specified.",
    1020           0 :                         OutputsDoc(),
    1021           0 :                         RPCArgOptions{.skip_type_check = true}},
    1022           0 :                     {"reduce_output", RPCArg::Type::NUM, RPCArg::DefaultHint{"not set, detect change automatically"}, "The 0-based index of the output from which the additional fees will be deducted. In general, this should be the position of change output. Cannot be provided if 'outputs' is specified."},
    1023             :                 },
    1024           0 :                 RPCArgOptions{.oneline_description="options"}},
    1025             :         },
    1026           0 :         RPCResult{
    1027           0 :             RPCResult::Type::OBJ, "", "", Cat(
    1028           0 :                 want_psbt ?
    1029           0 :                 std::vector<RPCResult>{{RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction."}} :
    1030           0 :                 std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction."}},
    1031           0 :             {
    1032           0 :                 {RPCResult::Type::STR_AMOUNT, "origfee", "The fee of the replaced transaction."},
    1033           0 :                 {RPCResult::Type::STR_AMOUNT, "fee", "The fee of the new transaction."},
    1034           0 :                 {RPCResult::Type::ARR, "errors", "Errors encountered during processing (may be empty).",
    1035           0 :                 {
    1036           0 :                     {RPCResult::Type::STR, "", ""},
    1037             :                 }},
    1038             :             })
    1039             :         },
    1040           0 :         RPCExamples{
    1041           0 :     "\nBump the fee, get the new transaction\'s " + std::string(want_psbt ? "psbt" : "txid") + "\n" +
    1042           0 :             HelpExampleCli(method_name, "<txid>")
    1043             :         },
    1044           0 :         [want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1045             : {
    1046           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
    1047           0 :     if (!pwallet) return UniValue::VNULL;
    1048             : 
    1049           0 :     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER) && !want_psbt) {
    1050           0 :         throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
    1051             :     }
    1052             : 
    1053           0 :     uint256 hash(ParseHashV(request.params[0], "txid"));
    1054             : 
    1055           0 :     CCoinControl coin_control;
    1056           0 :     coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
    1057             :     // optional parameters
    1058           0 :     coin_control.m_signal_bip125_rbf = true;
    1059           0 :     std::vector<CTxOut> outputs;
    1060             : 
    1061           0 :     std::optional<uint32_t> reduce_output;
    1062             : 
    1063           0 :     if (!request.params[1].isNull()) {
    1064           0 :         UniValue options = request.params[1];
    1065           0 :         RPCTypeCheckObj(options,
    1066           0 :             {
    1067           0 :                 {"confTarget", UniValueType(UniValue::VNUM)},
    1068           0 :                 {"conf_target", UniValueType(UniValue::VNUM)},
    1069           0 :                 {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
    1070           0 :                 {"replaceable", UniValueType(UniValue::VBOOL)},
    1071           0 :                 {"estimate_mode", UniValueType(UniValue::VSTR)},
    1072           0 :                 {"outputs", UniValueType()}, // will be checked by AddOutputs()
    1073           0 :                 {"reduce_output", UniValueType(UniValue::VNUM)},
    1074             :             },
    1075             :             true, true);
    1076             : 
    1077           0 :         if (options.exists("confTarget") && options.exists("conf_target")) {
    1078           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and conf_target options should not both be set. Use conf_target (confTarget is deprecated).");
    1079             :         }
    1080             : 
    1081           0 :         auto conf_target = options.exists("confTarget") ? options["confTarget"] : options["conf_target"];
    1082             : 
    1083           0 :         if (options.exists("replaceable")) {
    1084           0 :             coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
    1085           0 :         }
    1086           0 :         SetFeeEstimateMode(*pwallet, coin_control, conf_target, options["estimate_mode"], options["fee_rate"], /*override_min_fee=*/false);
    1087             : 
    1088             :         // Prepare new outputs by creating a temporary tx and calling AddOutputs().
    1089           0 :         if (!options["outputs"].isNull()) {
    1090           0 :             if (options["outputs"].isArray() && options["outputs"].empty()) {
    1091           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument cannot be an empty array");
    1092             :             }
    1093           0 :             CMutableTransaction tempTx;
    1094           0 :             AddOutputs(tempTx, options["outputs"]);
    1095           0 :             outputs = tempTx.vout;
    1096           0 :         }
    1097             : 
    1098           0 :         if (options.exists("reduce_output")) {
    1099           0 :             reduce_output = options["reduce_output"].getInt<uint32_t>();
    1100           0 :         }
    1101           0 :     }
    1102             : 
    1103             :     // Make sure the results are valid at least up to the most recent block
    1104             :     // the user could have gotten from another RPC command prior to now
    1105           0 :     pwallet->BlockUntilSyncedToCurrentChain();
    1106             : 
    1107           0 :     LOCK(pwallet->cs_wallet);
    1108             : 
    1109           0 :     EnsureWalletIsUnlocked(*pwallet);
    1110             : 
    1111             : 
    1112           0 :     std::vector<bilingual_str> errors;
    1113             :     CAmount old_fee;
    1114             :     CAmount new_fee;
    1115           0 :     CMutableTransaction mtx;
    1116             :     feebumper::Result res;
    1117             :     // Targeting feerate bump.
    1118           0 :     res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx, /*require_mine=*/ !want_psbt, outputs, reduce_output);
    1119           0 :     if (res != feebumper::Result::OK) {
    1120           0 :         switch(res) {
    1121             :             case feebumper::Result::INVALID_ADDRESS_OR_KEY:
    1122           0 :                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0].original);
    1123             :                 break;
    1124             :             case feebumper::Result::INVALID_REQUEST:
    1125           0 :                 throw JSONRPCError(RPC_INVALID_REQUEST, errors[0].original);
    1126             :                 break;
    1127             :             case feebumper::Result::INVALID_PARAMETER:
    1128           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0].original);
    1129             :                 break;
    1130             :             case feebumper::Result::WALLET_ERROR:
    1131           0 :                 throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
    1132             :                 break;
    1133             :             default:
    1134           0 :                 throw JSONRPCError(RPC_MISC_ERROR, errors[0].original);
    1135             :                 break;
    1136             :         }
    1137             :     }
    1138             : 
    1139           0 :     UniValue result(UniValue::VOBJ);
    1140             : 
    1141             :     // For bumpfee, return the new transaction id.
    1142             :     // For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction.
    1143           0 :     if (!want_psbt) {
    1144           0 :         if (!feebumper::SignTransaction(*pwallet, mtx)) {
    1145           0 :             if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
    1146           0 :                 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction incomplete. Try psbtbumpfee instead.");
    1147             :             }
    1148           0 :             throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
    1149             :         }
    1150             : 
    1151           0 :         uint256 txid;
    1152           0 :         if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
    1153           0 :             throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
    1154             :         }
    1155             : 
    1156           0 :         result.pushKV("txid", txid.GetHex());
    1157           0 :     } else {
    1158           0 :         PartiallySignedTransaction psbtx(mtx);
    1159           0 :         bool complete = false;
    1160           0 :         const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, /*sign=*/false, /*bip32derivs=*/true);
    1161           0 :         CHECK_NONFATAL(err == TransactionError::OK);
    1162           0 :         CHECK_NONFATAL(!complete);
    1163           0 :         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1164           0 :         ssTx << psbtx;
    1165           0 :         result.pushKV("psbt", EncodeBase64(ssTx.str()));
    1166           0 :     }
    1167             : 
    1168           0 :     result.pushKV("origfee", ValueFromAmount(old_fee));
    1169           0 :     result.pushKV("fee", ValueFromAmount(new_fee));
    1170           0 :     UniValue result_errors(UniValue::VARR);
    1171           0 :     for (const bilingual_str& error : errors) {
    1172           0 :         result_errors.push_back(error.original);
    1173             :     }
    1174           0 :     result.pushKV("errors", result_errors);
    1175             : 
    1176           0 :     return result;
    1177           0 : },
    1178             :     };
    1179           0 : }
    1180             : 
    1181           0 : RPCHelpMan bumpfee() { return bumpfee_helper("bumpfee"); }
    1182           0 : RPCHelpMan psbtbumpfee() { return bumpfee_helper("psbtbumpfee"); }
    1183             : 
    1184           0 : RPCHelpMan send()
    1185             : {
    1186           0 :     return RPCHelpMan{"send",
    1187           0 :         "\nEXPERIMENTAL warning: this call may be changed in future releases.\n"
    1188             :         "\nSend a transaction.\n",
    1189           0 :         {
    1190           0 :             {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs specified as key-value pairs.\n"
    1191             :                     "Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n"
    1192             :                     "At least one output of either type must be specified.\n"
    1193             :                     "For convenience, a dictionary, which holds the key-value pairs directly, is also accepted.",
    1194           0 :                 OutputsDoc(),
    1195           0 :                 RPCArgOptions{.skip_type_check = true}},
    1196           0 :             {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
    1197           0 :             {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
    1198           0 :              "\"" + FeeModes("\"\n\"") + "\""},
    1199           0 :             {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
    1200           0 :             {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
    1201           0 :                 Cat<std::vector<RPCArg>>(
    1202           0 :                 {
    1203           0 :                     {"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"},"Automatically include coins from the wallet to cover the target amount.\n"},
    1204           0 :                     {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
    1205             :                                                           "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
    1206             :                                                           "If that happens, you will need to fund the transaction with different inputs and republish it."},
    1207           0 :                     {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."},
    1208           0 :                     {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."},
    1209           0 :                     {"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
    1210           0 :                     {"change_address", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
    1211           0 :                     {"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
    1212           0 :                     {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\" and \"bech32m\"."},
    1213           0 :                     {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
    1214           0 :                     {"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
    1215             :                                           "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
    1216             :                                           "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
    1217           0 :                     {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Specify inputs instead of adding them automatically. A JSON array of JSON objects",
    1218           0 :                         {
    1219           0 :                             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    1220           0 :                             {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    1221           0 :                             {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"},
    1222           0 :                             {"weight", RPCArg::Type::NUM, RPCArg::DefaultHint{"Calculated from wallet and solving data"}, "The maximum weight for this input, "
    1223             :                                         "including the weight of the outpoint and sequence number. "
    1224             :                                         "Note that signature sizes are not guaranteed to be consistent, "
    1225             :                                         "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures."
    1226             :                                         "Remember to convert serialized sizes to weight units when necessary."},
    1227             :                         },
    1228             :                     },
    1229           0 :                     {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
    1230           0 :                     {"lock_unspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
    1231           0 :                     {"psbt", RPCArg::Type::BOOL,  RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."},
    1232           0 :                     {"subtract_fee_from_outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Outputs to subtract the fee from, specified as integer indices.\n"
    1233             :                     "The fee will be equally deducted from the amount of each specified output.\n"
    1234             :                     "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
    1235             :                     "If no outputs are specified here, the sender pays the fee.",
    1236           0 :                         {
    1237           0 :                             {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
    1238             :                         },
    1239             :                     },
    1240             :                 },
    1241           0 :                 FundTxDoc()),
    1242           0 :                 RPCArgOptions{.oneline_description="options"}},
    1243             :         },
    1244           0 :         RPCResult{
    1245           0 :             RPCResult::Type::OBJ, "", "",
    1246           0 :                 {
    1247           0 :                     {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    1248           0 :                     {RPCResult::Type::STR_HEX, "txid", /*optional=*/true, "The transaction id for the send. Only 1 transaction is created regardless of the number of addresses."},
    1249           0 :                     {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "If add_to_wallet is false, the hex-encoded raw transaction with signature(s)"},
    1250           0 :                     {RPCResult::Type::STR, "psbt", /*optional=*/true, "If more signatures are needed, or if add_to_wallet is false, the base64-encoded (partially) signed transaction"}
    1251             :                 }
    1252             :         },
    1253           0 :         RPCExamples{""
    1254             :         "\nSend 0.1 BTC with a confirmation target of 6 blocks in economical fee estimate mode\n"
    1255           0 :         + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 6 economical\n") +
    1256           0 :         "Send 0.2 BTC with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB using positional arguments\n"
    1257           0 :         + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.2}' null \"unset\" 1.1\n") +
    1258           0 :         "Send 0.2 BTC with a fee rate of 1 " + CURRENCY_ATOM + "/vB using the options argument\n"
    1259           0 :         + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.2}' null \"unset\" null '{\"fee_rate\": 1}'\n") +
    1260           0 :         "Send 0.3 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n"
    1261           0 :         + HelpExampleCli("-named send", "outputs='{\"" + EXAMPLE_ADDRESS[0] + "\": 0.3}' fee_rate=25\n") +
    1262             :         "Create a transaction that should confirm the next block, with a specific input, and return result without adding to wallet or broadcasting to the network\n"
    1263           0 :         + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 economical '{\"add_to_wallet\": false, \"inputs\": [{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\", \"vout\":1}]}'")
    1264             :         },
    1265           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1266             :         {
    1267           0 :             std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
    1268           0 :             if (!pwallet) return UniValue::VNULL;
    1269             : 
    1270           0 :             UniValue options{request.params[4].isNull() ? UniValue::VOBJ : request.params[4]};
    1271           0 :             InterpretFeeEstimationInstructions(/*conf_target=*/request.params[1], /*estimate_mode=*/request.params[2], /*fee_rate=*/request.params[3], options);
    1272           0 :             PreventOutdatedOptions(options);
    1273             : 
    1274             : 
    1275             :             CAmount fee;
    1276             :             int change_position;
    1277           0 :             bool rbf{options.exists("replaceable") ? options["replaceable"].get_bool() : pwallet->m_signal_rbf};
    1278           0 :             CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf);
    1279           0 :             CCoinControl coin_control;
    1280             :             // Automatically select coins, unless at least one is manually selected. Can
    1281             :             // be overridden by options.add_inputs.
    1282           0 :             coin_control.m_allow_other_inputs = rawTx.vin.size() == 0;
    1283           0 :             SetOptionsInputWeights(options["inputs"], options);
    1284           0 :             FundTransaction(*pwallet, rawTx, fee, change_position, options, coin_control, /*override_min_fee=*/false);
    1285             : 
    1286           0 :             return FinishTransaction(pwallet, options, rawTx);
    1287           0 :         }
    1288             :     };
    1289           0 : }
    1290             : 
    1291           0 : RPCHelpMan sendall()
    1292             : {
    1293           0 :     return RPCHelpMan{"sendall",
    1294           0 :         "EXPERIMENTAL warning: this call may be changed in future releases.\n"
    1295             :         "\nSpend the value of all (or specific) confirmed UTXOs in the wallet to one or more recipients.\n"
    1296             :         "Unconfirmed inbound UTXOs and locked UTXOs will not be spent. Sendall will respect the avoid_reuse wallet flag.\n"
    1297             :         "If your wallet contains many small inputs, either because it received tiny payments or as a result of accumulating change, consider using `send_max` to exclude inputs that are worth less than the fees needed to spend them.\n",
    1298           0 :         {
    1299           0 :             {"recipients", RPCArg::Type::ARR, RPCArg::Optional::NO, "The sendall destinations. Each address may only appear once.\n"
    1300             :                 "Optionally some recipients can be specified with an amount to perform payments, but at least one address must appear without a specified amount.\n",
    1301           0 :                 {
    1302           0 :                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "A bitcoin address which receives an equal share of the unspecified amount."},
    1303           0 :                     {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
    1304           0 :                         {
    1305           0 :                             {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
    1306             :                         },
    1307             :                     },
    1308             :                 },
    1309             :             },
    1310           0 :             {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
    1311           0 :             {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
    1312           0 :              "\"" + FeeModes("\"\n\"") + "\""},
    1313           0 :             {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
    1314           0 :             {
    1315           0 :                 "options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
    1316           0 :                 Cat<std::vector<RPCArg>>(
    1317           0 :                     {
    1318           0 :                         {"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns the serialized transaction without broadcasting or adding it to the wallet"},
    1319           0 :                         {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
    1320           0 :                         {"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch-only.\n"
    1321             :                                               "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
    1322             :                                               "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
    1323           0 :                         {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with the send_max, minconf, and maxconf options.",
    1324           0 :                             {
    1325           0 :                                 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    1326           0 :                                     {
    1327           0 :                                         {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    1328           0 :                                         {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    1329           0 :                                         {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"},
    1330             :                                     },
    1331             :                                 },
    1332             :                             },
    1333             :                         },
    1334           0 :                         {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
    1335           0 :                         {"lock_unspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
    1336           0 :                         {"psbt", RPCArg::Type::BOOL,  RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."},
    1337           0 :                         {"send_max", RPCArg::Type::BOOL, RPCArg::Default{false}, "When true, only use UTXOs that can pay for their own fees to maximize the output amount. When 'false' (default), no UTXO is left behind. send_max is incompatible with providing specific inputs."},
    1338           0 :                         {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Require inputs with at least this many confirmations."},
    1339           0 :                         {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Require inputs with at most this many confirmations."},
    1340             :                     },
    1341           0 :                     FundTxDoc()
    1342             :                 ),
    1343           0 :                 RPCArgOptions{.oneline_description="options"}
    1344             :             },
    1345             :         },
    1346           0 :         RPCResult{
    1347           0 :             RPCResult::Type::OBJ, "", "",
    1348           0 :                 {
    1349           0 :                     {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    1350           0 :                     {RPCResult::Type::STR_HEX, "txid", /*optional=*/true, "The transaction id for the send. Only 1 transaction is created regardless of the number of addresses."},
    1351           0 :                     {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "If add_to_wallet is false, the hex-encoded raw transaction with signature(s)"},
    1352           0 :                     {RPCResult::Type::STR, "psbt", /*optional=*/true, "If more signatures are needed, or if add_to_wallet is false, the base64-encoded (partially) signed transaction"}
    1353             :                 }
    1354             :         },
    1355           0 :         RPCExamples{""
    1356           0 :         "\nSpend all UTXOs from the wallet with a fee rate of 1 " + CURRENCY_ATOM + "/vB using named arguments\n"
    1357           0 :         + HelpExampleCli("-named sendall", "recipients='[\"" + EXAMPLE_ADDRESS[0] + "\"]' fee_rate=1\n") +
    1358           0 :         "Spend all UTXOs with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB using positional arguments\n"
    1359           0 :         + HelpExampleCli("sendall", "'[\"" + EXAMPLE_ADDRESS[0] + "\"]' null \"unset\" 1.1\n") +
    1360           0 :         "Spend all UTXOs split into equal amounts to two addresses with a fee rate of 1.5 " + CURRENCY_ATOM + "/vB using the options argument\n"
    1361           0 :         + HelpExampleCli("sendall", "'[\"" + EXAMPLE_ADDRESS[0] + "\", \"" + EXAMPLE_ADDRESS[1] + "\"]' null \"unset\" null '{\"fee_rate\": 1.5}'\n") +
    1362           0 :         "Leave dust UTXOs in wallet, spend only UTXOs with positive effective value with a fee rate of 10 " + CURRENCY_ATOM + "/vB using the options argument\n"
    1363           0 :         + HelpExampleCli("sendall", "'[\"" + EXAMPLE_ADDRESS[0] + "\"]' null \"unset\" null '{\"fee_rate\": 10, \"send_max\": true}'\n") +
    1364           0 :         "Spend all UTXOs with a fee rate of 1.3 " + CURRENCY_ATOM + "/vB using named arguments and sending a 0.25 " + CURRENCY_UNIT + " to another recipient\n"
    1365           0 :         + HelpExampleCli("-named sendall", "recipients='[{\"" + EXAMPLE_ADDRESS[1] + "\": 0.25}, \""+ EXAMPLE_ADDRESS[0] + "\"]' fee_rate=1.3\n")
    1366             :         },
    1367           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1368             :         {
    1369           0 :             std::shared_ptr<CWallet> const pwallet{GetWalletForJSONRPCRequest(request)};
    1370           0 :             if (!pwallet) return UniValue::VNULL;
    1371             :             // Make sure the results are valid at least up to the most recent block
    1372             :             // the user could have gotten from another RPC command prior to now
    1373           0 :             pwallet->BlockUntilSyncedToCurrentChain();
    1374             : 
    1375           0 :             UniValue options{request.params[4].isNull() ? UniValue::VOBJ : request.params[4]};
    1376           0 :             InterpretFeeEstimationInstructions(/*conf_target=*/request.params[1], /*estimate_mode=*/request.params[2], /*fee_rate=*/request.params[3], options);
    1377           0 :             PreventOutdatedOptions(options);
    1378             : 
    1379             : 
    1380           0 :             std::set<std::string> addresses_without_amount;
    1381           0 :             UniValue recipient_key_value_pairs(UniValue::VARR);
    1382           0 :             const UniValue& recipients{request.params[0]};
    1383           0 :             for (unsigned int i = 0; i < recipients.size(); ++i) {
    1384           0 :                 const UniValue& recipient{recipients[i]};
    1385           0 :                 if (recipient.isStr()) {
    1386           0 :                     UniValue rkvp(UniValue::VOBJ);
    1387           0 :                     rkvp.pushKV(recipient.get_str(), 0);
    1388           0 :                     recipient_key_value_pairs.push_back(rkvp);
    1389           0 :                     addresses_without_amount.insert(recipient.get_str());
    1390           0 :                 } else {
    1391           0 :                     recipient_key_value_pairs.push_back(recipient);
    1392             :                 }
    1393           0 :             }
    1394             : 
    1395           0 :             if (addresses_without_amount.size() == 0) {
    1396           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Must provide at least one address without a specified amount");
    1397             :             }
    1398             : 
    1399           0 :             CCoinControl coin_control;
    1400             : 
    1401           0 :             SetFeeEstimateMode(*pwallet, coin_control, options["conf_target"], options["estimate_mode"], options["fee_rate"], /*override_min_fee=*/false);
    1402             : 
    1403           0 :             coin_control.fAllowWatchOnly = ParseIncludeWatchonly(options["include_watching"], *pwallet);
    1404             : 
    1405           0 :             if (options.exists("minconf")) {
    1406           0 :                 if (options["minconf"].getInt<int>() < 0)
    1407             :                 {
    1408           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid minconf (minconf cannot be negative): %s", options["minconf"].getInt<int>()));
    1409             :                 }
    1410             : 
    1411           0 :                 coin_control.m_min_depth = options["minconf"].getInt<int>();
    1412           0 :             }
    1413             : 
    1414           0 :             if (options.exists("maxconf")) {
    1415           0 :                 coin_control.m_max_depth = options["maxconf"].getInt<int>();
    1416             : 
    1417           0 :                 if (coin_control.m_max_depth < coin_control.m_min_depth) {
    1418           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coin_control.m_max_depth, coin_control.m_min_depth));
    1419             :                 }
    1420           0 :             }
    1421             : 
    1422           0 :             const bool rbf{options.exists("replaceable") ? options["replaceable"].get_bool() : pwallet->m_signal_rbf};
    1423             : 
    1424           0 :             FeeCalculation fee_calc_out;
    1425           0 :             CFeeRate fee_rate{GetMinimumFeeRate(*pwallet, coin_control, &fee_calc_out)};
    1426             :             // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
    1427             :             // provided one
    1428           0 :             if (coin_control.m_feerate && fee_rate > *coin_control.m_feerate) {
    1429           0 :                throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee rate (%s) is lower than the minimum fee rate setting (%s)", coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), fee_rate.ToString(FeeEstimateMode::SAT_VB)));
    1430             :             }
    1431           0 :             if (fee_calc_out.reason == FeeReason::FALLBACK && !pwallet->m_allow_fallback_fee) {
    1432             :                 // eventually allow a fallback fee
    1433           0 :                 throw JSONRPCError(RPC_WALLET_ERROR, "Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
    1434             :             }
    1435             : 
    1436           0 :             CMutableTransaction rawTx{ConstructTransaction(options["inputs"], recipient_key_value_pairs, options["locktime"], rbf)};
    1437           0 :             LOCK(pwallet->cs_wallet);
    1438             : 
    1439           0 :             CAmount total_input_value(0);
    1440           0 :             bool send_max{options.exists("send_max") ? options["send_max"].get_bool() : false};
    1441           0 :             if (options.exists("inputs") && options.exists("send_max")) {
    1442           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot combine send_max with specific inputs.");
    1443           0 :             } else if (options.exists("inputs") && (options.exists("minconf") || options.exists("maxconf"))) {
    1444           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot combine minconf or maxconf with specific inputs.");
    1445           0 :             } else if (options.exists("inputs")) {
    1446           0 :                 for (const CTxIn& input : rawTx.vin) {
    1447           0 :                     if (pwallet->IsSpent(input.prevout)) {
    1448           0 :                         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not available. UTXO (%s:%d) was already spent.", input.prevout.hash.ToString(), input.prevout.n));
    1449             :                     }
    1450           0 :                     const CWalletTx* tx{pwallet->GetWalletTx(input.prevout.hash)};
    1451           0 :                     if (!tx || input.prevout.n >= tx->tx->vout.size() || !(pwallet->IsMine(tx->tx->vout[input.prevout.n]) & (coin_control.fAllowWatchOnly ? ISMINE_ALL : ISMINE_SPENDABLE))) {
    1452           0 :                         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not found. UTXO (%s:%d) is not part of wallet.", input.prevout.hash.ToString(), input.prevout.n));
    1453             :                     }
    1454           0 :                     total_input_value += tx->tx->vout[input.prevout.n].nValue;
    1455             :                 }
    1456           0 :             } else {
    1457           0 :                 CoinFilterParams coins_params;
    1458           0 :                 coins_params.min_amount = 0;
    1459           0 :                 for (const COutput& output : AvailableCoins(*pwallet, &coin_control, fee_rate, coins_params).All()) {
    1460           0 :                     CHECK_NONFATAL(output.input_bytes > 0);
    1461           0 :                     if (send_max && fee_rate.GetFee(output.input_bytes) > output.txout.nValue) {
    1462           0 :                         continue;
    1463             :                     }
    1464           0 :                     CTxIn input(output.outpoint.hash, output.outpoint.n, CScript(), rbf ? MAX_BIP125_RBF_SEQUENCE : CTxIn::SEQUENCE_FINAL);
    1465           0 :                     rawTx.vin.push_back(input);
    1466           0 :                     total_input_value += output.txout.nValue;
    1467           0 :                 }
    1468             :             }
    1469             : 
    1470             :             // estimate final size of tx
    1471           0 :             const TxSize tx_size{CalculateMaximumSignedTxSize(CTransaction(rawTx), pwallet.get())};
    1472           0 :             const CAmount fee_from_size{fee_rate.GetFee(tx_size.vsize)};
    1473           0 :             const CAmount effective_value{total_input_value - fee_from_size};
    1474             : 
    1475           0 :             if (fee_from_size > pwallet->m_default_max_tx_fee) {
    1476           0 :                 throw JSONRPCError(RPC_WALLET_ERROR, TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED).original);
    1477             :             }
    1478             : 
    1479           0 :             if (effective_value <= 0) {
    1480           0 :                 if (send_max) {
    1481           0 :                     throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Total value of UTXO pool too low to pay for transaction, try using lower feerate.");
    1482             :                 } else {
    1483           0 :                     throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Total value of UTXO pool too low to pay for transaction. Try using lower feerate or excluding uneconomic UTXOs with 'send_max' option.");
    1484             :                 }
    1485             :             }
    1486             : 
    1487             :             // If this transaction is too large, e.g. because the wallet has many UTXOs, it will be rejected by the node's mempool.
    1488           0 :             if (tx_size.weight > MAX_STANDARD_TX_WEIGHT) {
    1489           0 :                 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction too large.");
    1490             :             }
    1491             : 
    1492           0 :             CAmount output_amounts_claimed{0};
    1493           0 :             for (const CTxOut& out : rawTx.vout) {
    1494           0 :                 output_amounts_claimed += out.nValue;
    1495             :             }
    1496             : 
    1497           0 :             if (output_amounts_claimed > total_input_value) {
    1498           0 :                 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Assigned more value to outputs than available funds.");
    1499             :             }
    1500             : 
    1501           0 :             const CAmount remainder{effective_value - output_amounts_claimed};
    1502           0 :             if (remainder < 0) {
    1503           0 :                 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds for fees after creating specified outputs.");
    1504             :             }
    1505             : 
    1506           0 :             const CAmount per_output_without_amount{remainder / (long)addresses_without_amount.size()};
    1507             : 
    1508           0 :             bool gave_remaining_to_first{false};
    1509           0 :             for (CTxOut& out : rawTx.vout) {
    1510           0 :                 CTxDestination dest;
    1511           0 :                 ExtractDestination(out.scriptPubKey, dest);
    1512           0 :                 std::string addr{EncodeDestination(dest)};
    1513           0 :                 if (addresses_without_amount.count(addr) > 0) {
    1514           0 :                     out.nValue = per_output_without_amount;
    1515           0 :                     if (!gave_remaining_to_first) {
    1516           0 :                         out.nValue += remainder % addresses_without_amount.size();
    1517           0 :                         gave_remaining_to_first = true;
    1518           0 :                     }
    1519           0 :                     if (IsDust(out, pwallet->chain().relayDustFee())) {
    1520             :                         // Dynamically generated output amount is dust
    1521           0 :                         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Dynamically assigned remainder results in dust output.");
    1522             :                     }
    1523           0 :                 } else {
    1524           0 :                     if (IsDust(out, pwallet->chain().relayDustFee())) {
    1525             :                         // Specified output amount is dust
    1526           0 :                         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Specified output amount to %s is below dust threshold.", addr));
    1527             :                     }
    1528             :                 }
    1529           0 :             }
    1530             : 
    1531           0 :             const bool lock_unspents{options.exists("lock_unspents") ? options["lock_unspents"].get_bool() : false};
    1532           0 :             if (lock_unspents) {
    1533           0 :                 for (const CTxIn& txin : rawTx.vin) {
    1534           0 :                     pwallet->LockCoin(txin.prevout);
    1535             :                 }
    1536           0 :             }
    1537             : 
    1538           0 :             return FinishTransaction(pwallet, options, rawTx);
    1539           0 :         }
    1540             :     };
    1541           0 : }
    1542             : 
    1543           0 : RPCHelpMan walletprocesspsbt()
    1544             : {
    1545           0 :     return RPCHelpMan{"walletprocesspsbt",
    1546             :                 "\nUpdate a PSBT with input information from our wallet and then sign inputs\n"
    1547           0 :                 "that we can sign for." +
    1548             :         HELP_REQUIRING_PASSPHRASE,
    1549           0 :                 {
    1550           0 :                     {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
    1551           0 :                     {"sign", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also sign the transaction when updating (requires wallet to be unlocked)"},
    1552           0 :                     {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT for Taproot, ALL otherwise"}, "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
    1553             :             "       \"DEFAULT\"\n"
    1554             :             "       \"ALL\"\n"
    1555             :             "       \"NONE\"\n"
    1556             :             "       \"SINGLE\"\n"
    1557             :             "       \"ALL|ANYONECANPAY\"\n"
    1558             :             "       \"NONE|ANYONECANPAY\"\n"
    1559             :             "       \"SINGLE|ANYONECANPAY\""},
    1560           0 :                     {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
    1561           0 :                     {"finalize", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also finalize inputs if possible"},
    1562             :                 },
    1563           0 :                 RPCResult{
    1564           0 :                     RPCResult::Type::OBJ, "", "",
    1565           0 :                     {
    1566           0 :                         {RPCResult::Type::STR, "psbt", "The base64-encoded partially signed transaction"},
    1567           0 :                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    1568           0 :                         {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "The hex-encoded network transaction if complete"},
    1569             :                     }
    1570             :                 },
    1571           0 :                 RPCExamples{
    1572           0 :                     HelpExampleCli("walletprocesspsbt", "\"psbt\"")
    1573             :                 },
    1574           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1575             : {
    1576           0 :     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
    1577           0 :     if (!pwallet) return UniValue::VNULL;
    1578             : 
    1579           0 :     const CWallet& wallet{*pwallet};
    1580             :     // Make sure the results are valid at least up to the most recent block
    1581             :     // the user could have gotten from another RPC command prior to now
    1582           0 :     wallet.BlockUntilSyncedToCurrentChain();
    1583             : 
    1584             :     // Unserialize the transaction
    1585           0 :     PartiallySignedTransaction psbtx;
    1586           0 :     std::string error;
    1587           0 :     if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
    1588           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
    1589             :     }
    1590             : 
    1591             :     // Get the sighash type
    1592           0 :     int nHashType = ParseSighashString(request.params[2]);
    1593             : 
    1594             :     // Fill transaction with our data and also sign
    1595           0 :     bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
    1596           0 :     bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
    1597           0 :     bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool();
    1598           0 :     bool complete = true;
    1599             : 
    1600           0 :     if (sign) EnsureWalletIsUnlocked(*pwallet);
    1601             : 
    1602           0 :     const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs, nullptr, finalize)};
    1603           0 :     if (err != TransactionError::OK) {
    1604           0 :         throw JSONRPCTransactionError(err);
    1605             :     }
    1606             : 
    1607           0 :     UniValue result(UniValue::VOBJ);
    1608           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1609           0 :     ssTx << psbtx;
    1610           0 :     result.pushKV("psbt", EncodeBase64(ssTx.str()));
    1611           0 :     result.pushKV("complete", complete);
    1612           0 :     if (complete) {
    1613           0 :         CMutableTransaction mtx;
    1614             :         // Returns true if complete, which we already think it is.
    1615           0 :         CHECK_NONFATAL(FinalizeAndExtractPSBT(psbtx, mtx));
    1616           0 :         CDataStream ssTx_final(SER_NETWORK, PROTOCOL_VERSION);
    1617           0 :         ssTx_final << mtx;
    1618           0 :         result.pushKV("hex", HexStr(ssTx_final));
    1619           0 :     }
    1620             : 
    1621           0 :     return result;
    1622           0 : },
    1623             :     };
    1624           0 : }
    1625             : 
    1626           0 : RPCHelpMan walletcreatefundedpsbt()
    1627             : {
    1628           0 :     return RPCHelpMan{"walletcreatefundedpsbt",
    1629           0 :                 "\nCreates and funds a transaction in the Partially Signed Transaction format.\n"
    1630             :                 "Implements the Creator and Updater roles.\n"
    1631             :                 "All existing inputs must either have their previous output transaction be in the wallet\n"
    1632             :                 "or be in the UTXO set. Solving data must be provided for non-wallet inputs.\n",
    1633           0 :                 {
    1634           0 :                     {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Leave empty to add inputs automatically. See add_inputs option.",
    1635           0 :                         {
    1636           0 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    1637           0 :                                 {
    1638           0 :                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    1639           0 :                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    1640           0 :                                     {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'locktime' and 'options.replaceable' arguments"}, "The sequence number"},
    1641           0 :                                     {"weight", RPCArg::Type::NUM, RPCArg::DefaultHint{"Calculated from wallet and solving data"}, "The maximum weight for this input, "
    1642             :                                         "including the weight of the outpoint and sequence number. "
    1643             :                                         "Note that signature sizes are not guaranteed to be consistent, "
    1644             :                                         "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures."
    1645             :                                         "Remember to convert serialized sizes to weight units when necessary."},
    1646             :                                 },
    1647             :                             },
    1648             :                         },
    1649             :                         },
    1650           0 :                     {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs specified as key-value pairs.\n"
    1651             :                             "Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n"
    1652             :                             "At least one output of either type must be specified.\n"
    1653             :                             "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
    1654             :                             "accepted as second parameter.",
    1655           0 :                         OutputsDoc(),
    1656           0 :                         RPCArgOptions{.skip_type_check = true}},
    1657           0 :                     {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
    1658           0 :                     {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
    1659           0 :                         Cat<std::vector<RPCArg>>(
    1660           0 :                         {
    1661           0 :                             {"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"}, "Automatically include coins from the wallet to cover the target amount.\n"},
    1662           0 :                             {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
    1663             :                                                           "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
    1664             :                                                           "If that happens, you will need to fund the transaction with different inputs and republish it."},
    1665           0 :                             {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."},
    1666           0 :                             {"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."},
    1667           0 :                             {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
    1668           0 :                             {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
    1669           0 :                             {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
    1670           0 :                             {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"},
    1671           0 :                             {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
    1672           0 :                             {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
    1673           0 :                             {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
    1674           0 :                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The outputs to subtract the fee from.\n"
    1675             :                                                           "The fee will be equally deducted from the amount of each specified output.\n"
    1676             :                                                           "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
    1677             :                                                           "If no outputs are specified here, the sender pays the fee.",
    1678           0 :                                 {
    1679           0 :                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
    1680             :                                 },
    1681             :                             },
    1682             :                         },
    1683           0 :                         FundTxDoc()),
    1684           0 :                         RPCArgOptions{.oneline_description="options"}},
    1685           0 :                     {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
    1686             :                 },
    1687           0 :                 RPCResult{
    1688           0 :                     RPCResult::Type::OBJ, "", "",
    1689           0 :                     {
    1690           0 :                         {RPCResult::Type::STR, "psbt", "The resulting raw transaction (base64-encoded string)"},
    1691           0 :                         {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
    1692           0 :                         {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
    1693             :                     }
    1694             :                                 },
    1695           0 :                                 RPCExamples{
    1696             :                             "\nCreate a transaction with no inputs\n"
    1697           0 :                             + HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
    1698             :                                 },
    1699           0 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1700             : {
    1701           0 :     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
    1702           0 :     if (!pwallet) return UniValue::VNULL;
    1703             : 
    1704           0 :     CWallet& wallet{*pwallet};
    1705             :     // Make sure the results are valid at least up to the most recent block
    1706             :     // the user could have gotten from another RPC command prior to now
    1707           0 :     wallet.BlockUntilSyncedToCurrentChain();
    1708             : 
    1709           0 :     UniValue options{request.params[3].isNull() ? UniValue::VOBJ : request.params[3]};
    1710             : 
    1711             :     CAmount fee;
    1712             :     int change_position;
    1713           0 :     const UniValue &replaceable_arg = options["replaceable"];
    1714           0 :     const bool rbf{replaceable_arg.isNull() ? wallet.m_signal_rbf : replaceable_arg.get_bool()};
    1715           0 :     CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
    1716           0 :     CCoinControl coin_control;
    1717             :     // Automatically select coins, unless at least one is manually selected. Can
    1718             :     // be overridden by options.add_inputs.
    1719           0 :     coin_control.m_allow_other_inputs = rawTx.vin.size() == 0;
    1720           0 :     SetOptionsInputWeights(request.params[0], options);
    1721           0 :     FundTransaction(wallet, rawTx, fee, change_position, options, coin_control, /*override_min_fee=*/true);
    1722             : 
    1723             :     // Make a blank psbt
    1724           0 :     PartiallySignedTransaction psbtx(rawTx);
    1725             : 
    1726             :     // Fill transaction with out data but don't sign
    1727           0 :     bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
    1728           0 :     bool complete = true;
    1729           0 :     const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, /*sign=*/false, /*bip32derivs=*/bip32derivs)};
    1730           0 :     if (err != TransactionError::OK) {
    1731           0 :         throw JSONRPCTransactionError(err);
    1732             :     }
    1733             : 
    1734             :     // Serialize the PSBT
    1735           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1736           0 :     ssTx << psbtx;
    1737             : 
    1738           0 :     UniValue result(UniValue::VOBJ);
    1739           0 :     result.pushKV("psbt", EncodeBase64(ssTx.str()));
    1740           0 :     result.pushKV("fee", ValueFromAmount(fee));
    1741           0 :     result.pushKV("changepos", change_position);
    1742           0 :     return result;
    1743           0 : },
    1744             :     };
    1745           0 : }
    1746             : } // namespace wallet

Generated by: LCOV version 1.14