Coverage Report

Created: 2026-09-14 20:36

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