protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            if (WalletManager.Network == Network.Main)
            {
                Logger.LogInfo("WabiSabi coinjoin client-side functionality is disabled temporarily on mainnet.");
                return;
            }
            var trackedWallets = new Dictionary <string, WalletTrackingData>();

            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken).ConfigureAwait(false);

                var mixableWallets = GetMixableWallets();
                var openedWallets  = mixableWallets.Where(x => !trackedWallets.ContainsKey(x.Key));
                var closedWallets  = trackedWallets.Where(x => !mixableWallets.ContainsKey(x.Key));

                foreach (var openedWallet in openedWallets.Select(x => x.Value))
                {
                    var coinjoinClient = new CoinJoinClient(ArenaRequestHandler, openedWallet.Kitchen, openedWallet.KeyManager, RoundStatusUpdater);
                    var cts            = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
                    var coinCandidates = openedWallet.Coins.Available().Confirmed().Where(x => x.HdPubKey.AnonymitySet < ServiceConfiguration.GetMixUntilAnonymitySetValue());
                    var coinjoinTask   = coinjoinClient.StartCoinJoinAsync(coinCandidates, cts.Token);

                    trackedWallets.Add(openedWallet.WalletName, new WalletTrackingData(openedWallet, coinjoinClient, coinjoinTask, cts));
                }

                foreach (var closedWallet in closedWallets.Select(x => x.Value))
                {
                    closedWallet.CancellationTokenSource.Cancel();
                    closedWallet.CancellationTokenSource.Dispose();
                }

                var finishedCoinJoins = trackedWallets
                                        .Where(x => x.Value.CoinJoinTask.IsCompleted)
                                        .Select(x => x.Value)
                                        .ToImmutableArray();

                foreach (var finishedCoinJoin in finishedCoinJoins)
                {
                    var removed = trackedWallets.Remove(finishedCoinJoin.Wallet.WalletName);
                    if (!removed)
                    {
                        Logger.LogWarning($"Wallet: `{finishedCoinJoin.Wallet.WalletName}` was not removed from tracked wallet list. Will retry in a few seconds.");
                    }
                    finishedCoinJoin.CancellationTokenSource.Dispose();
                }

                foreach (var finishedCoinJoin in finishedCoinJoins)
                {
                    var logPrefix = $"Wallet: `{finishedCoinJoin.Wallet.WalletName}` - Coinjoin client";
                    try
                    {
                        var success = await finishedCoinJoin.CoinJoinTask.ConfigureAwait(false);

                        if (success)
                        {
                            Logger.LogInfo($"{logPrefix} finished successfully!");
                        }
                        else
                        {
                            Logger.LogInfo($"{logPrefix} finished with error. Transaction not broadcasted.");
                        }
                    }
                    catch (InvalidOperationException ioe)
                    {
                        Logger.LogError(ioe);
                        await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.LogInfo($"{logPrefix} was cancelled.");
                    }
                    catch (Exception e)
                    {
                        Logger.LogError($"{logPrefix} failed with exception:", e);
                    }
                }

                TrackedWallets = trackedWallets.ToImmutableDictionary();
            }
        }
 private record WalletTrackingData(Wallet Wallet, CoinJoinClient CoinJoinClient, Task <bool> CoinJoinTask, CancellationTokenSource CancellationTokenSource);