Coverage Report

Created: 2025-06-10 13:21

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