Skip to content

Commit 15e97a6

Browse files
committed
wallet: add SelectionResult::GetChange
1 parent 72cad28 commit 15e97a6

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

src/wallet/coinselection.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,11 @@ CAmount SelectionResult::GetSelectedValue() const
421421
return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin.txout.nValue; });
422422
}
423423

424+
CAmount SelectionResult::GetSelectedEffectiveValue() const
425+
{
426+
return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin.GetEffectiveValue(); });
427+
}
428+
424429
void SelectionResult::Clear()
425430
{
426431
m_selected_inputs.clear();
@@ -480,4 +485,24 @@ std::string GetAlgorithmName(const SelectionAlgorithm algo)
480485
}
481486
assert(false);
482487
}
488+
489+
CAmount SelectionResult::GetChange(const CAmount min_viable_change, const CAmount change_fee) const
490+
{
491+
// change = SUM(inputs) - SUM(outputs) - fees
492+
// 1) With SFFO we don't pay any fees
493+
// 2) Otherwise we pay all the fees:
494+
// - input fees are covered by GetSelectedEffectiveValue()
495+
// - non_input_fee is included in m_target
496+
// - change_fee
497+
const CAmount change = m_use_effective
498+
? GetSelectedEffectiveValue() - m_target - change_fee
499+
: GetSelectedValue() - m_target;
500+
501+
if (change < min_viable_change) {
502+
return 0;
503+
}
504+
505+
return change;
506+
}
507+
483508
} // namespace wallet

src/wallet/coinselection.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ struct SelectionResult
303303
/** Get the sum of the input values */
304304
[[nodiscard]] CAmount GetSelectedValue() const;
305305

306+
[[nodiscard]] CAmount GetSelectedEffectiveValue() const;
307+
306308
void Clear();
307309

308310
void AddInput(const OutputGroup& group);
@@ -320,6 +322,25 @@ struct SelectionResult
320322

321323
bool operator<(SelectionResult other) const;
322324

325+
/** Get the amount for the change output after paying needed fees.
326+
*
327+
* The change amount is not 100% precise due to discrepancies in fee calculation.
328+
* The final change amount (if any) should be corrected after calculating the final tx fees.
329+
* When there is a discrepancy, most of the time the final change would be slightly bigger than estimated.
330+
*
331+
* Following are the possible factors of discrepancy:
332+
* + non-input fees always include segwit flags
333+
* + input fee estimation always include segwit stack size
334+
* + input fees are rounded individually and not collectively, which leads to small rounding errors
335+
* - input counter size is always assumed to be 1vbyte
336+
*
337+
* @param[in] min_viable_change Minimum amount for change output, if change would be less then we forgo change
338+
* @param[in] change_fee Fees to include change output in the tx
339+
* @returns Amount for change output, 0 when there is no change.
340+
*
341+
*/
342+
CAmount GetChange(const CAmount min_viable_change, const CAmount change_fee) const;
343+
323344
CAmount GetTarget() const { return m_target; }
324345

325346
SelectionAlgorithm GetAlgo() const { return m_algo; }

0 commit comments

Comments
 (0)