Coverage Report

Created: 2026-07-14 18:13

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