make optimized transactions reproducible
MODIFY
WalletWasabi.Fluent/Helpers/TransactionHelpers.cs
WalletWasabi.Fluent/Helpers/TransactionHelpers.cs
@@ -18,6 +18,23 @@ namespace WalletWasabi.Fluent.Helpers
{
public static class TransactionHelpers
{
+ public static BuildTransactionResult BuildChangelessTransaction(Wallet wallet, BitcoinAddress address, SmartLabel labels, FeeRate feeRate, IEnumerable<SmartCoin> coins)
+ {
+ var intent = new PaymentIntent(
+ address,
+ MoneyRequest.CreateAllRemaining(subtractFee: true),
+ labels);
+
+ var txRes = wallet.BuildTransaction(
+ wallet.Kitchen.SaltSoup(),
+ intent,
+ FeeStrategy.CreateFromFeeRate(feeRate),
+ allowUnconfirmed: true,
+ coins.Select(coin => coin.OutPoint));
+
+ return txRes;
+ }
+
public static BuildTransactionResult BuildTransaction(Wallet wallet, BitcoinAddress address, Money amount, SmartLabel labels, FeeRate feeRate, IEnumerable<SmartCoin> coins, bool subtractFee, IPayjoinClient? payJoinClient = null)
{
if (payJoinClient is { } && subtractFee)
@@ -44,6 +61,16 @@ namespace WalletWasabi.Fluent.Helpers
public static BuildTransactionResult BuildTransaction(Wallet wallet, TransactionInfo transactionInfo, bool isPayJoin = false)
{
+ if (transactionInfo.IsOptimized)
+ {
+ return BuildChangelessTransaction(
+ wallet,
+ transactionInfo.Address,
+ transactionInfo.UserLabels,
+ transactionInfo.FeeRate,
+ transactionInfo.ChangelessCoins);
+ }
+
if (isPayJoin && transactionInfo.SubtractFee)
{
throw new InvalidOperationException("Not possible to subtract the fee.");

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/OptimisePrivacyViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/OptimisePrivacyViewModel.cs
@@ -56,7 +56,14 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
private void Complete()
{
- Close(DialogResultKind.Normal, SelectedPrivacySuggestion!.TransactionResult);
+ var selectedTxn = SelectedPrivacySuggestion!.TransactionResult;
+
+ if (selectedTxn != _requestedTransaction)
+ {
+ _transactionInfo.ChangelessCoins = selectedTxn.SpentCoins;
+ }
+
+ Close(DialogResultKind.Normal, selectedTxn);
}
protected override void OnNavigatedTo(bool inHistory, CompositeDisposable disposables)
@@ -69,25 +76,19 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
{
IsBusy = true;
- var intent = new PaymentIntent(
- _transactionInfo.Address,
- MoneyRequest.CreateAllRemaining(subtractFee: true),
- _transactionInfo.UserLabels);
-
PrivacySuggestionControlViewModel? smallerSuggestion = null;
if (_requestedTransaction.SpentCoins.Count() > 1)
{
- var smallerTransaction = await Task.Run(() => _wallet.BuildTransaction(
- _wallet.Kitchen.SaltSoup(),
- intent,
- FeeStrategy.CreateFromFeeRate(_transactionInfo.FeeRate),
- allowUnconfirmed: true,
- _requestedTransaction
+ var smallerTransaction = await Task.Run(() =>
+ {
+ var coins = _requestedTransaction
.SpentCoins
.OrderBy(x => x.Amount)
- .Skip(1)
- .Select(x => x.OutPoint)));
+ .Skip(1);
+
+ return TransactionHelpers.BuildChangelessTransaction(_wallet, _transactionInfo.Address, _transactionInfo.UserLabels, _transactionInfo.FeeRate, coins);
+ });
smallerSuggestion = new PrivacySuggestionControlViewModel(
_transactionInfo.Amount.ToDecimal(MoneyUnit.BTC), smallerTransaction,
@@ -98,12 +99,12 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
_transactionInfo.Amount.ToDecimal(MoneyUnit.BTC), _requestedTransaction,
PrivacyOptimisationLevel.Standard, _wallet.Synchronizer.UsdExchangeRate, new PrivacySuggestionBenefit(false, "As Requested"));
- var largerTransaction = await Task.Run(() => _wallet.BuildTransaction(
- _wallet.Kitchen.SaltSoup(),
- intent,
- FeeStrategy.CreateFromFeeRate(_transactionInfo.FeeRate),
- true,
- _requestedTransaction.SpentCoins.Select(x => x.OutPoint)));
+ var largerTransaction = await Task.Run(() =>
+ {
+ var coins = _requestedTransaction.SpentCoins;
+
+ return TransactionHelpers.BuildChangelessTransaction(_wallet, _transactionInfo.Address, _transactionInfo.UserLabels, _transactionInfo.FeeRate, coins);
+ });
var largerSuggestion = new PrivacySuggestionControlViewModel(
_transactionInfo.Amount.ToDecimal(MoneyUnit.BTC), largerTransaction,

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionInfo.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionInfo.cs
@@ -34,10 +34,14 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
public IEnumerable<SmartCoin> Coins { get; set; } = Enumerable.Empty<SmartCoin>();
+ public IEnumerable<SmartCoin> ChangelessCoins { get; set; } = Enumerable.Empty<SmartCoin>();
+
public IPayjoinClient? PayJoinClient { get; set; }
public bool IsPayJoin => PayJoinClient is { };
+ public bool IsOptimized => ChangelessCoins.Any();
+
public bool IsPrivatePocketUsed => Coins.All(x => x.HdPubKey.AnonymitySet >= _privateCoinThreshold);
public bool SubtractFee { get; set; }
@@ -46,6 +50,7 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
{
SubtractFee = default;
FeeRate = FeeRate.Zero;
+ ChangelessCoins = Enumerable.Empty<SmartCoin>();
if (Coins.Sum(x => x.Amount) < Amount) // Reset coins if the selected cluster is not enough for the new amount
{

make optimized transactions reproducible