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