diff --git a/src/subcommand/wallet/transaction_builder.rs b/src/subcommand/wallet/transaction_builder.rs index ebdecf6a79..fcfb322e76 100644 --- a/src/subcommand/wallet/transaction_builder.rs +++ b/src/subcommand/wallet/transaction_builder.rs @@ -697,7 +697,13 @@ impl TransactionBuilder { current_value >= target_value && is_closer }; - if is_preference_and_closer || not_preference_but_closer { + let newly_meets_preference = if prefer_under { + best_value > target_value && current_value <= target_value + } else { + best_value < target_value && current_value >= target_value + }; + + if is_preference_and_closer || not_preference_but_closer || newly_meets_preference { best_match = Some((*utxo, current_value)) } } @@ -1979,4 +1985,58 @@ mod tests { outpoint(2), ); } + + #[test] + fn prefer_further_away_utxos_if_they_are_newly_under_target() { + let utxos = vec![ + (outpoint(1), Amount::from_sat(510)), + (outpoint(2), Amount::from_sat(400)), + ]; + + let mut tx_builder = TransactionBuilder::new( + satpoint(0, 0), + BTreeMap::new(), + utxos.into_iter().collect(), + BTreeSet::new(), + recipient(), + [change(0), change(1)], + FeeRate::try_from(1.0).unwrap(), + Target::Value(Amount::from_sat(10_000)), + ); + + assert_eq!( + tx_builder + .select_cardinal_utxo(Amount::from_sat(500), true) + .unwrap() + .0, + outpoint(2), + ); + } + + #[test] + fn prefer_further_away_utxos_if_they_are_newly_over_target() { + let utxos = vec![ + (outpoint(1), Amount::from_sat(490)), + (outpoint(2), Amount::from_sat(600)), + ]; + + let mut tx_builder = TransactionBuilder::new( + satpoint(0, 0), + BTreeMap::new(), + utxos.into_iter().collect(), + BTreeSet::new(), + recipient(), + [change(0), change(1)], + FeeRate::try_from(1.0).unwrap(), + Target::Value(Amount::from_sat(10_000)), + ); + + assert_eq!( + tx_builder + .select_cardinal_utxo(Amount::from_sat(500), false) + .unwrap() + .0, + outpoint(2), + ); + } }