spend.cpp raw

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