Skip to content

Commit

Permalink
wallet: Add coin control option "change_target"
Browse files Browse the repository at this point in the history
Add a coin control rpc parameter to optionally force a particular change target for coin selection algorithms that result in a change output.
  • Loading branch information
remyers committed Aug 22, 2024
1 parent 0cbdc6b commit 86e6207
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/wallet/coincontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class CCoinControl
std::optional<uint32_t> m_locktime;
//! Version
std::optional<uint32_t> m_version;
//! Use this change target instead of default behavior if set
std::optional<CAmount> m_change_target;

CCoinControl();

Expand Down
8 changes: 8 additions & 0 deletions src/wallet/rpc/spend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransact
{"minconf", UniValueType(UniValue::VNUM)},
{"maxconf", UniValueType(UniValue::VNUM)},
{"input_weights", UniValueType(UniValue::VARR)},
{"change_target", UniValueType()}, // will be checked by AmountFromValue() below
},
true, true);

Expand Down Expand Up @@ -702,6 +703,10 @@ CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransact
}
}

if (options.exists("change_target")) {
coinControl.m_change_target = CAmount(AmountFromValue(options["change_target"]));
}

if (recipients.empty())
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");

Expand Down Expand Up @@ -787,6 +792,7 @@ RPCHelpMan fundrawtransaction()
},
},
},
{"change_target", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to default wallet behavior"}, "Specify a target change amount in " + CURRENCY_UNIT + "."},
},
FundTxDoc()),
RPCArgOptions{
Expand Down Expand Up @@ -1241,6 +1247,7 @@ RPCHelpMan send()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
{"change_target", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to default wallet behavior"}, "Specify a target change amount in " + CURRENCY_UNIT + "."},
},
FundTxDoc()),
RPCArgOptions{.oneline_description="options"}},
Expand Down Expand Up @@ -1690,6 +1697,7 @@ RPCHelpMan walletcreatefundedpsbt()
{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
},
},
{"change_target", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to default wallet behavior"}, "Specify a target change amount in " + CURRENCY_UNIT + "."},
},
FundTxDoc()),
RPCArgOptions{.oneline_description="options"}},
Expand Down
6 changes: 5 additions & 1 deletion src/wallet/spend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,11 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
coin_selection_params.m_change_fee = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.change_output_size);
coin_selection_params.m_cost_of_change = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size) + coin_selection_params.m_change_fee;

coin_selection_params.m_min_change_target = GenerateChangeTarget(std::floor(recipients_sum / vecSend.size()), coin_selection_params.m_change_fee, rng_fast);
if (coin_control.m_change_target) {
coin_selection_params.m_min_change_target = coin_control.m_change_target.value();
} else {
coin_selection_params.m_min_change_target = GenerateChangeTarget(std::floor(recipients_sum / vecSend.size()), coin_selection_params.m_change_fee, rng_fast);
}

// The smallest change amount should be:
// 1. at least equal to dust threshold
Expand Down

0 comments on commit 86e6207

Please sign in to comment.