Coverage Report

Created: 2026-07-29 23:27

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