Add IsExcludedFromCoinJoin property and set it on load
MODIFY
WalletWasabi/Blockchain/Keys/KeyManager.cs
WalletWasabi/Blockchain/Keys/KeyManager.cs
@@ -203,6 +203,9 @@ public class KeyManager
[JsonProperty(Order = 999, PropertyName = "HdPubKeys")]
private List<HdPubKey> HdPubKeys { get; } = new();
+ [JsonProperty(ItemConverterType = typeof(OutPointJsonConverter), PropertyName = "ExcludedCoinsFromCoinJoin")]
+ public List<OutPoint> ExcludedCoinsFromCoinJoin { get; private set; } = new();
+
public string? FilePath { get; private set; }
[MemberNotNullWhen(returnValue: false, nameof(EncryptedSecret))]
@@ -706,6 +709,12 @@ public class KeyManager
private static HdPubKey CreateHdPubKey((KeyPath KeyPath, ExtPubKey ExtPubKey) x) =>
new(x.ExtPubKey.PubKey, x.KeyPath, SmartLabel.Empty, KeyState.Clean);
+
+ internal void SetExcludedCoinsFromCoinJoin(IEnumerable<OutPoint> excludedOutpoints)
+ {
+ ExcludedCoinsFromCoinJoin = excludedOutpoints.ToList();
+ ToFile();
+ }
}
public static class KeyPathExtensions

MODIFY
WalletWasabi/Blockchain/TransactionOutputs/SmartCoin.cs
WalletWasabi/Blockchain/TransactionOutputs/SmartCoin.cs
@@ -25,6 +25,7 @@ public class SmartCoin : NotifyPropertyChangedBase, IEquatable<SmartCoin>, IDest
private bool _confirmed;
private bool _isBanned;
+ private bool _isExcludedFromCoinJoin;
private Lazy<uint256> _transactionId;
private Lazy<OutPoint> _outPoint;
@@ -143,6 +144,12 @@ public class SmartCoin : NotifyPropertyChangedBase, IEquatable<SmartCoin>, IDest
private set => RaiseAndSetIfChanged(ref _isBanned, value);
}
+ public bool IsExcludedFromCoinJoin
+ {
+ get => _isExcludedFromCoinJoin;
+ set => RaiseAndSetIfChanged(ref _isExcludedFromCoinJoin, value);
+ }
+
public bool IsImmature(int bestHeight)
{
return Transaction.Transaction.IsCoinBase && Height < bestHeight - 100;
@@ -166,9 +173,9 @@ public class SmartCoin : NotifyPropertyChangedBase, IEquatable<SmartCoin>, IDest
public bool IsSpent() => SpenderTransaction is not null;
/// <summary>
- /// IsUnspent() AND !SpentAccordingToBackend AND !CoinJoinInProgress
+ /// IsUnspent() AND !SpentAccordingToBackend AND !CoinJoinInProgress AND !IsFrozen
/// </summary>
- public bool IsAvailable() => SpenderTransaction is null && !SpentAccordingToBackend && !CoinJoinInProgress;
+ public bool IsAvailable() => SpenderTransaction is null && !SpentAccordingToBackend && !CoinJoinInProgress && !IsExcludedFromCoinJoin;
public bool IsReplaceable() => Transaction.IsRBF;

MODIFY
WalletWasabi/Wallets/Wallet.cs
WalletWasabi/Wallets/Wallet.cs
@@ -224,6 +224,7 @@ public class Wallet : BackgroundService, IWallet
{
await LoadWalletStateAsync(cancel).ConfigureAwait(false);
await LoadDummyMempoolAsync().ConfigureAwait(false);
+ LoadExcludedCoins();
}
}
@@ -238,6 +239,27 @@ public class Wallet : BackgroundService, IWallet
}
}
+ private void LoadExcludedCoins()
+ {
+ bool isUpdateRequired = false;
+ foreach (var excludedCoin in KeyManager.ExcludedCoinsFromCoinJoin)
+ {
+ var coin = Coins.SingleOrDefault(c => c.Outpoint == excludedCoin);
+ if (coin != null)
+ {
+ coin.IsExcludedFromCoinJoin = true;
+ }
+ else
+ {
+ isUpdateRequired = true;
+ }
+ }
+ if (isUpdateRequired)
+ {
+ UpdateExcludedCoinFromCoinJoin();
+ }
+ }
+
/// <inheritdoc />
protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.CompletedTask;
@@ -504,6 +526,12 @@ public class Wallet : BackgroundService, IWallet
return wallet;
}
+ public void UpdateExcludedCoinFromCoinJoin()
+ {
+ var excludedOutpoints = Coins.Where(c => c.IsExcludedFromCoinJoin).Select(c => c.Outpoint);
+ KeyManager.SetExcludedCoinsFromCoinJoin(excludedOutpoints);
+ }
+
public bool IsMixable =>
State == WalletState.Started // Only running wallets
&& !KeyManager.IsWatchOnly // that are not watch-only wallets

Add IsExcludedFromCoinJoin property and set it on load