[Fluent] Implement some privacy control logic
# Conflicts:
#	WalletWasabi.Fluent/ViewModels/Wallets/Send/OptimisePrivacyViewModel.cs
MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/OptimisePrivacyViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/OptimisePrivacyViewModel.cs
+using NBitcoin;
+using System.Collections;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive.Concurrency;
+using System.Reactive.Disposables;
+using ReactiveUI;
+using WalletWasabi.Blockchain.TransactionBuilding;
+using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Fluent.ViewModels.Navigation;
+using WalletWasabi.Wallets;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
{
[NavigationMetaData(Title = "Optimise your privacy")]
public partial class OptimisePrivacyViewModel : RoutableViewModel
{
+ private readonly TransactionInfo _transactionInfo;
+ private readonly Wallet _wallet;
+ private readonly BuildTransactionResult _requestedTransaction;
+
[AutoNotify] private ObservableCollection<PrivacySuggestionControlViewModel> _privacySuggestions;
- [AutoNotify] private PrivacySuggestionControlViewModel _selectedPrivacySuggestion;
+ [AutoNotify] private PrivacySuggestionControlViewModel? _selectedPrivacySuggestion;
- public OptimisePrivacyViewModel()
+ public OptimisePrivacyViewModel(Wallet wallet,
+ TransactionInfo transactionInfo, BuildTransactionResult requestedTransaction)
{
+ _wallet = wallet;
+ _requestedTransaction = requestedTransaction;
+ _transactionInfo = transactionInfo;
+
_privacySuggestions = new ObservableCollection<PrivacySuggestionControlViewModel>();
+ }
- _privacySuggestions.Add(new PrivacySuggestionControlViewModel
+ protected override void OnNavigatedTo(bool inStack, CompositeDisposable disposables)
{
- Title = "1.13 BTC",
- Caption = "Less",
- Benefits = new[]
- {
- "Send 0.01% Less",
- "Improved Privacy",
- "Save on transaction fees"
- },
- OptimisationLevel = PrivacyOptimisationLevel.Better
- });
+ IsBusy = true;
+ base.OnNavigatedTo(inStack, disposables);
- _privacySuggestions.Add(new PrivacySuggestionControlViewModel
+ RxApp.MainThreadScheduler.Schedule(async () =>
{
- Title = "1.2 BTC",
- Caption = "Standard",
- Benefits = new[]
- {
- "Send Exact Amount"
- },
- OptimisationLevel = PrivacyOptimisationLevel.Standard
- });
+ var intent = new PaymentIntent(
+ destination: _transactionInfo.Address,
+ amount: MoneyRequest.CreateAllRemaining(subtractFee: true),
+ label: _transactionInfo.Labels);
- _privacySuggestions.Add(new PrivacySuggestionControlViewModel
+ if (_requestedTransaction.SpentCoins.Count() > 1)
{
- Title = "1.27 BTC",
- Caption = "Extra",
- Benefits = new[]
- {
- "Send 0.01% More",
- "Improved Privacy",
- "Save on transaction fees"
- },
- OptimisationLevel = PrivacyOptimisationLevel.Better
- });
+ var smallerTransaction = _wallet.BuildTransaction(
+ _wallet.Kitchen.SaltSoup(),
+ intent,
+ FeeStrategy.CreateFromFeeRate(_transactionInfo.FeeRate),
+ allowUnconfirmed: true,
+ _requestedTransaction
+ .SpentCoins
+ .OrderBy(x => x.Amount)
+ .Skip(1)
+ .Select(x => x.OutPoint));
- SelectedPrivacySuggestion = _privacySuggestions[1];
+ _privacySuggestions.Add(new PrivacySuggestionControlViewModel(smallerTransaction));
+ }
+
+ var exactSuggestion = new PrivacySuggestionControlViewModel(_requestedTransaction);
+
+ _privacySuggestions.Add(exactSuggestion);
+
+ var largerTransaction = _wallet.BuildTransaction(
+ _wallet.Kitchen.SaltSoup(),
+ intent,
+ FeeStrategy.CreateFromFeeRate(_transactionInfo.FeeRate),
+ allowUnconfirmed: true,
+ _requestedTransaction.SpentCoins.Select(x => x.OutPoint));
+
+ _privacySuggestions.Add(new PrivacySuggestionControlViewModel(largerTransaction));
+
+ SelectedPrivacySuggestion = exactSuggestion;
+
+ IsBusy = false;
+ });
}
}
}

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacySuggestionControlViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacySuggestionControlViewModel.cs
+using WalletWasabi.Blockchain.TransactionBuilding;
+
namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
{
public enum PrivacyOptimisationLevel
@@ -8,6 +10,13 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
public partial class PrivacySuggestionControlViewModel : ViewModelBase
{
+ private readonly BuildTransactionResult _transactionResult;
+
+ public PrivacySuggestionControlViewModel(BuildTransactionResult transactionResult)
+ {
+ _transactionResult = transactionResult;
+ }
+
[AutoNotify] private string _title;
[AutoNotify] private string _caption;
[AutoNotify] private string[] _benefits;

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/SendViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/SendViewModel.cs
@@ -90,7 +90,6 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
NextCommand = ReactiveCommand.Create(() =>
{
- var password = "foo";
var transactionInfo = _transactionInfo;
var wallet = _owner.Wallet;
var targetAnonset = wallet.ServiceConfiguration.GetMixUntilAnonymitySetValue();
@@ -105,17 +104,18 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
try
{
var txRes = wallet.BuildTransaction(
- password,
+ wallet.Kitchen.SaltSoup(),
intent,
FeeStrategy.CreateFromFeeRate(transactionInfo.FeeRate),
allowUnconfirmed: true,
mixedCoins.Select(x => x.OutPoint));
- // private coins enough.
- Navigate().To(new OptimisePrivacyViewModel());
+
+ // Private coins are enough.
+ Navigate().To(new OptimisePrivacyViewModel(wallet, transactionInfo, txRes));
}
catch (NotEnoughFundsException)
{
- // not enough private coins
+ // Not enough private coins.
Navigate().To(new PrivacyControlViewModel());
}
});

MODIFY
WalletWasabi/Wallets/Wallet.cs
WalletWasabi/Wallets/Wallet.cs
@@ -95,7 +95,7 @@ namespace WalletWasabi.Wallets
public bool IsLoggedIn { get; private set; }
- private Kitchen Kitchen { get; } = new();
+ public Kitchen Kitchen { get; } = new();
public void Login(string password)
{

[Fluent] Implement some privacy control logic

# Conflicts:
#	WalletWasabi.Fluent/ViewModels/Wallets/Send/OptimisePrivacyViewModel.cs