Coverage Report

Created: 2026-10-07 13:27

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