Consider TargetAnonset separate private and unlabelled
MODIFY
WalletWasabi.Fluent/Helpers/CoinPocketHelper.cs
WalletWasabi.Fluent/Helpers/CoinPocketHelper.cs
@@ -10,12 +10,18 @@ namespace WalletWasabi.Fluent.Helpers
{
public static class CoinPocketHelper
{
- public static IEnumerable<(string Labels, ICoinsView Coins)> GetPockets(this ICoinsView allCoins, int anonymitySet)
+ public const string UnlabelledFundsText = "Unlabelled Funds";
+ public const string PrivateFundsText = "Private Funds";
+
+ public static IEnumerable<(string Labels, ICoinsView Coins)> GetPockets(this ICoinsView allCoins, int privateAnonSetThreshold)
{
- var clusters = allCoins.Where(x=>x.HdPubKey.AnonymitySet < anonymitySet)
+ List<(string Labels, ICoinsView Coins)> pockets = new();
+
+ var clusters = allCoins
+ .Where(x => x.HdPubKey.AnonymitySet < privateAnonSetThreshold)
.GroupBy(x => x.HdPubKey.Cluster.Labels);
- List<(string Labels, ICoinsView Coins)> pockets = new();
+ CoinsView? unLabelledCoins = null;
foreach (var cluster in clusters)
{
@@ -24,8 +30,7 @@ namespace WalletWasabi.Fluent.Helpers
if (string.IsNullOrWhiteSpace(allLabels))
{
- // If the Label is empty then add every coin as a separate pocket
- pockets.Add(new("Unlabelled Funds", new CoinsView(coins)));
+ unLabelledCoins = new CoinsView(coins);
}
else
{
@@ -33,7 +38,16 @@ namespace WalletWasabi.Fluent.Helpers
}
}
- pockets.Add(new("Private Funds", new CoinsView(allCoins.Where(x=>x.HdPubKey.AnonymitySet >= anonymitySet))));
+ if (unLabelledCoins is { })
+ {
+ pockets.Add(new(UnlabelledFundsText, unLabelledCoins));
+ }
+
+ var privateCoins = new CoinsView(allCoins.Where(x => x.HdPubKey.AnonymitySet >= privateAnonSetThreshold));
+ if (privateCoins.Any())
+ {
+ pockets.Add(new(PrivateFundsText, privateCoins));
+ }
return pockets;
}

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacyControlViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacyControlViewModel.cs
@@ -28,7 +28,7 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
{
base.OnNavigatedTo(isInHistory, disposables);
- var pockets = _wallet.Coins.GetPockets(2);
+ var pockets = _wallet.Coins.GetPockets(_wallet.ServiceConfiguration.GetMixUntilAnonymitySetValue());
foreach (var pocket in pockets)
{

MODIFY
WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs
WalletWasabi.Tests/UnitTests/Transactions/TransactionProcessorTests.cs
@@ -1073,6 +1073,7 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
[Fact]
public async Task GetPocketsAsync()
{
+ int targetAnonSet = 60;
var transactionProcessor = await CreateTransactionProcessorAsync();
transactionProcessor.Process(CreateCreditingTransaction(transactionProcessor.NewKey("A").P2wpkhScript, Money.Coins(1.0m)));
transactionProcessor.Process(CreateCreditingTransaction(transactionProcessor.NewKey("A").P2wpkhScript, Money.Coins(1.0m)));
@@ -1084,16 +1085,29 @@ namespace WalletWasabi.Tests.UnitTests.Transactions
transactionProcessor.Process(CreateCreditingTransaction(transactionProcessor.NewKey("").P2wpkhScript, Money.Coins(1.0m)));
transactionProcessor.Process(CreateCreditingTransaction(transactionProcessor.NewKey("").P2wpkhScript, Money.Coins(1.0m)));
transactionProcessor.Process(CreateCreditingTransaction(transactionProcessor.NewKey("").P2wpkhScript, Money.Coins(1.0m)));
- transactionProcessor.Process(CreateCreditingTransaction(transactionProcessor.NewKey("").P2wpkhScript, Money.Coins(1.0m)));
- IEnumerable<(string Labels, ICoinsView Coins)> pockets = CoinPocketHelper.GetPockets(transactionProcessor.Coins, 2);
+ var notYetPrivateCoin = transactionProcessor.NewKey("");
+ transactionProcessor.Process(CreateCreditingTransaction(notYetPrivateCoin.P2wpkhScript, Money.Coins(1.0m)));
+ notYetPrivateCoin.AnonymitySet = targetAnonSet - 1;
+
+ var privateCoin1 = transactionProcessor.NewKey("");
+ transactionProcessor.Process(CreateCreditingTransaction(privateCoin1.P2wpkhScript, Money.Coins(1.0m)));
+ privateCoin1.AnonymitySet = targetAnonSet;
+
+ var privateCoin2 = transactionProcessor.NewKey("");
+ transactionProcessor.Process(CreateCreditingTransaction(privateCoin2.P2wpkhScript, Money.Coins(1.0m)));
+ privateCoin2.AnonymitySet = targetAnonSet;
+
+ IEnumerable<(string Labels, ICoinsView Coins)> pockets = CoinPocketHelper.GetPockets(transactionProcessor.Coins, targetAnonSet);
(string Labels, ICoinsView Coins) aPocket = pockets.Single(x => x.Labels == "A");
+
Assert.Equal(3, aPocket.Coins.Count());
Assert.Equal(Money.Coins(3.0m), aPocket.Coins.TotalAmount());
Assert.Single(pockets.Single(x => x.Labels == "B").Coins);
Assert.Equal(2, pockets.Single(x => x.Labels == "C").Coins.Count());
Assert.Single(pockets.Single(x => x.Labels == "A, B").Coins);
- Assert.Equal(4, pockets.Count(x => x.Labels == ""));
+ Assert.Equal(4, pockets.Single(x => x.Labels == CoinPocketHelper.UnlabelledFundsText).Coins.Count());
+ Assert.Equal(2, pockets.Single(x => x.Labels == CoinPocketHelper.PrivateFundsText).Coins.Count());
}
private static SmartTransaction CreateSpendingTransaction(Coin coin, Script? scriptPubKey = null, int height = 0)

Consider TargetAnonset separate private and unlabelled