Coverage Report

Created: 2026-05-30 09:47

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