wallet: introduce setfeerate, an improved settxfee in sat/vB

Github-Pull: #20391
Rebased-From: 8e863e3d3ce457c9ca26a12e8fd6beac2f50aa7d (diff-minimised)
This commit is contained in:
Jon Atack 2020-11-14 15:38:40 +01:00 committed by Luke Dashjr
parent 01e51a3976
commit eda384078d
3 changed files with 77 additions and 0 deletions

View File

@ -47,6 +47,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendtoaddress", 8, "avoid_reuse" },
{ "sendtoaddress", 9, "fee_rate"},
{ "sendtoaddress", 10, "verbose"},
{ "setfeerate", 0, "amount" },
{ "settxfee", 0, "amount" },
{ "sethdseed", 0, "newkeypool" },
{ "getreceivedbyaddress", 1, "minconf" },

View File

@ -408,6 +408,80 @@ RPCHelpMan sendmany()
};
}
RPCHelpMan setfeerate()
{
return RPCHelpMan{
"setfeerate",
"\nSet the transaction fee rate in " + CURRENCY_ATOM + "/vB for this wallet.\n"
"Overrides the global -paytxfee configuration option. Like -paytxfee, it is not persisted after bitcoind shutdown/restart.\n"
"Can be deactivated by passing 0 as the fee rate, in which case automatic fee selection will be used by default.\n",
{
{"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee rate in " + CURRENCY_ATOM + "/vB to set (0 to unset)"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "wallet_name", "Name of the wallet the fee rate setting applies to"},
{RPCResult::Type::NUM, "fee_rate", "Fee rate in " + CURRENCY_ATOM + "/vB for the wallet after this operation"},
{RPCResult::Type::STR, "result", /* optional */ true, "Description of result, if successful"},
{RPCResult::Type::STR, "error", /* optional */ true, "Description of error, if any"},
},
},
RPCExamples{
""
"\nSet a fee rate of 1 " + CURRENCY_ATOM + "/vB\n"
+ HelpExampleCli("setfeerate", "1") +
"\nSet a fee rate of 3.141 " + CURRENCY_ATOM + "/vB\n"
+ HelpExampleCli("setfeerate", "3.141") +
"\nSet a fee rate of 7.75 " + CURRENCY_ATOM + "/vB with named arguments\n"
+ HelpExampleCli("-named setfeerate", "amount=\"7.75\"") +
"\nSet a fee rate of 25 " + CURRENCY_ATOM + "/vB with the RPC\n"
+ HelpExampleRpc("setfeerate", "25")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
std::shared_ptr<CWallet> const rpc_wallet{GetWalletForJSONRPCRequest(request)};
if (!rpc_wallet) return NullUniValue;
CWallet& wallet = *rpc_wallet;
LOCK(wallet.cs_wallet);
const CFeeRate amount{AmountFromValue(request.params[0]), COIN /* sat/vB */};
const CFeeRate relay_min_feerate{wallet.chain().relayMinFee().GetFeePerK()};
const CFeeRate wallet_min_feerate{wallet.m_min_fee.GetFeePerK()};
const CFeeRate wallet_max_feerate{wallet.m_default_max_tx_fee, 1000 /* BTC/kvB */};
const CFeeRate zero{CFeeRate{0}};
const std::string amount_str{amount.ToString(FeeEstimateMode::SAT_VB)};
const std::string current_setting{strprintf("The current setting of %s for this wallet remains unchanged.", wallet.m_pay_tx_fee == zero ? "0 (unset)" : wallet.m_pay_tx_fee.ToString(FeeEstimateMode::SAT_VB))};
std::string result, error;
if (amount == zero) {
if (request.params[0].get_real() != 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
wallet.m_pay_tx_fee = amount;
result = "Fee rate for transactions with this wallet successfully unset. By default, automatic fee selection will be used.";
} else if (amount < relay_min_feerate) {
error = strprintf("The requested fee rate of %s cannot be less than the minimum relay fee rate of %s. %s", amount_str, relay_min_feerate.ToString(FeeEstimateMode::SAT_VB), current_setting);
} else if (amount < wallet_min_feerate) {
error = strprintf("The requested fee rate of %s cannot be less than the wallet min fee rate of %s. %s", amount_str, wallet_min_feerate.ToString(FeeEstimateMode::SAT_VB), current_setting);
} else if (amount > wallet_max_feerate) {
error = strprintf("The requested fee rate of %s cannot be greater than the wallet max fee rate of %s. %s", amount_str, wallet_max_feerate.ToString(FeeEstimateMode::SAT_VB), current_setting);
} else {
wallet.m_pay_tx_fee = amount;
result = "Fee rate for transactions with this wallet successfully set to " + amount_str;
}
CHECK_NONFATAL(result.empty() != error.empty());
UniValue obj{UniValue::VOBJ};
obj.pushKV("wallet_name", wallet.GetName());
obj.pushKV("fee_rate", ValueFromFeeRate(wallet.m_pay_tx_fee));
if (error.empty()) {
obj.pushKV("result", result);
} else {
obj.pushKV("error", error);
}
return obj;
},
};
}
RPCHelpMan settxfee()
{
return RPCHelpMan{"settxfee",

View File

@ -866,6 +866,7 @@ RPCHelpMan encryptwallet();
// spend
RPCHelpMan sendtoaddress();
RPCHelpMan sendmany();
RPCHelpMan setfeerate();
RPCHelpMan settxfee();
RPCHelpMan fundrawtransaction();
RPCHelpMan bumpfee();
@ -945,6 +946,7 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &sendtoaddress},
{"wallet", &sethdseed},
{"wallet", &setlabel},
{"wallet", &setfeerate},
{"wallet", &settxfee},
{"wallet", &setwalletflag},
{"wallet", &signmessage},