private async Task <GetDepositAddressResponse> GeCircleDepositAddressAsync(GetDepositAddressRequest request)
        {
            try
            {
                var asset = _circleAssetMapper.AssetToCircleAsset(request.BrokerId, request.AssetSymbol);

                if (asset == null || string.IsNullOrEmpty(asset.CircleAsset))
                {
                    _logger.LogError(
                        "Cannot process GetDepositAddress. Asset do not mapped to circle. Request: {jsonText}",
                        JsonConvert.SerializeObject(request));
                    return(new GetDepositAddressResponse
                    {
                        Error = GetDepositAddressResponse.ErrorCode.AssetDoNotSupported
                    });
                }

                await using var ctx = DatabaseContext.Create(_dbContextOptionsBuilder);
                var addressEntity = await ctx.Addresses.Where(t =>
                                                              t.BrokerId == request.BrokerId && t.ClientId == request.ClientId &&
                                                              t.WalletId == request.WalletId && t.Blockchain == request.Blockchain &&
                                                              t.AssetSymbol == request.AssetSymbol).FirstOrDefaultAsync();

                var address = addressEntity?.Address;

                string error = null;
                if (string.IsNullOrEmpty(address))
                {
                    var preGeneratedAddresses = (await _generatedAddressDataWriter.GetAsync(
                                                     GeneratedDepositAddressEntity.GeneratePartitionKey(request.BrokerId, asset.CircleAsset,
                                                                                                        asset.CircleWalletId, request.Blockchain)))
                                                .ToList();

                    if (preGeneratedAddresses.Count > 0)
                    {
                        var preGeneratedAddress = preGeneratedAddresses.First();
                        address = preGeneratedAddress.Address.Address;
                        await _generatedAddressDataWriter.DeleteAsync(preGeneratedAddress.PartitionKey,
                                                                      preGeneratedAddress.RowKey);
                    }
                    else
                    {
                        var id       = Guid.NewGuid().ToString();
                        var response = await _circleDepositAddressService.GenerateDepositAddress(
                            new CreateCircleDepositAddressRequest
                        {
                            RequestGuid = id,
                            BrokerId    = asset.BrokerId,
                            Asset       = request.AssetSymbol,
                            Blockchain  = request.Blockchain
                        });

                        if (!response.IsSuccess)
                        {
                            _logger.LogError(
                                "Unable to pre-generate address for broker {broker}, asset {asset}, wallet id {walletId}, blockchain  {blockchain}: {error}",
                                asset.BrokerId, request.AssetSymbol, asset.CircleWalletId, request.Blockchain,
                                response.ErrorMessage);
                        }

                        address = response.Data?.Address;
                        error   = response.ErrorMessage;
                    }
                }

                if (string.IsNullOrEmpty(address) || error != null)
                {
                    _logger.LogError(
                        "Cannot process GetDepositAddress. Unable to generate address. Request: {jsonText}. Error: {error}",
                        JsonConvert.SerializeObject(request), error);
                    return(new GetDepositAddressResponse
                    {
                        Error = GetDepositAddressResponse.ErrorCode.AddressNotGenerated
                    });
                }

                if (addressEntity == null)
                {
                    await ctx.InsertAsync(new DepositAddressSqlEntity
                    {
                        BrokerId    = request.BrokerId,
                        ClientId    = request.ClientId,
                        WalletId    = request.WalletId,
                        Integration = "Circle",
                        AssetSymbol = request.AssetSymbol,
                        Blockchain  = request.Blockchain,
                        Address     = address,
                        CreatedDate = DateTime.Now
                    });
                }

                await _addressDataWriter.InsertOrReplaceAsync(DepositAddressEntity.Create(request.WalletId,
                                                                                          request.AssetSymbol, request.Blockchain, address));

                await _addressDataWriter.CleanAndKeepMaxPartitions(Program.Settings.MaxClientInCache);

                _logger.LogInformation("Handle GetDepositAddress, request: {jsonText}, address: {address}",
                                       JsonConvert.SerializeObject(request), address);

                return(new GetDepositAddressResponse
                {
                    Address = address,
                    Error = GetDepositAddressResponse.ErrorCode.Ok
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception on GetDepositAddress with request: {jsonText}",
                                 JsonConvert.SerializeObject(request));
                throw;
            }
        }
        private async Task <GetDepositAddressResponse> GetBitgoDepositAddressAsync(GetDepositAddressRequest request)
        {
            try
            {
                var(bitgoCoin, bitgoWalletId) =
                    _assetMapper.AssetToBitgoCoinAndWallet(request.BrokerId, request.AssetSymbol);

                if (string.IsNullOrEmpty(bitgoWalletId) || string.IsNullOrEmpty(bitgoCoin))
                {
                    _logger.LogError(
                        "Cannot process GetDepositAddress. Asset do not mapped to bitgo. Request: {jsonText}",
                        JsonConvert.SerializeObject(request));
                    return(new GetDepositAddressResponse
                    {
                        Error = GetDepositAddressResponse.ErrorCode.AssetDoNotSupported
                    });
                }

                Error error = null;

                var label = _walletMapper.WalletToBitgoLabel(new JetWalletIdentity
                {
                    BrokerId = request.BrokerId,
                    ClientId = request.ClientId,
                    WalletId = request.WalletId
                });

                await using var ctx = DatabaseContext.Create(_dbContextOptionsBuilder);
                var addressEntity = await ctx.Addresses.Where(t =>
                                                              t.BrokerId == request.BrokerId && t.ClientId == request.ClientId &&
                                                              t.WalletId == request.WalletId && t.Blockchain == request.Blockchain &&
                                                              t.AssetSymbol == request.AssetSymbol).FirstOrDefaultAsync();

                var address = addressEntity?.Address;

                if (string.IsNullOrEmpty(address))
                {
                    (address, error) =
                        await _depositAddressGeneratorService.GetAddressAsync(bitgoCoin, bitgoWalletId, label);
                }

                if (string.IsNullOrEmpty(address))
                {
                    var preGeneratedAddresses = (await _generatedAddressDataWriter.GetAsync(
                                                     GeneratedDepositAddressEntity.GeneratePartitionKey(request.BrokerId, bitgoCoin,
                                                                                                        bitgoWalletId, request.Blockchain)))
                                                .ToList();

                    if (preGeneratedAddresses.Count > 0)
                    {
                        var preGeneratedAddress = preGeneratedAddresses.First();
                        (address, error) = await _depositAddressGeneratorService.UpdateAddressLabelAsync(bitgoCoin,
                                                                                                         bitgoWalletId,
                                                                                                         preGeneratedAddress.Address.BitGoAddressId, label);

                        if (error == null)
                        {
                            await _generatedAddressDataWriter.DeleteAsync(preGeneratedAddress.PartitionKey,
                                                                          preGeneratedAddress.RowKey);
                        }
                    }
                    else
                    {
                        (address, error) =
                            await _depositAddressGeneratorService.GenerateAddressAsync(bitgoCoin, bitgoWalletId, label);
                    }
                }

                if (string.IsNullOrEmpty(address) || error != null)
                {
                    _logger.LogError(
                        "Cannot process GetDepositAddress. Unable to generate address. Request: {jsonText}. Error: {error}",
                        JsonConvert.SerializeObject(request), error);
                    return(new GetDepositAddressResponse
                    {
                        Error = GetDepositAddressResponse.ErrorCode.AddressNotGenerated
                    });
                }

                if (addressEntity == null)
                {
                    await ctx.InsertAsync(new DepositAddressSqlEntity
                    {
                        BrokerId    = request.BrokerId,
                        ClientId    = request.ClientId,
                        WalletId    = request.WalletId,
                        Integration = "BitGo",
                        AssetSymbol = request.AssetSymbol,
                        Blockchain  = request.Blockchain,
                        Address     = address,
                        CreatedDate = DateTime.Now
                    });
                }

                await _addressDataWriter.InsertOrReplaceAsync(DepositAddressEntity.Create(request.WalletId,
                                                                                          request.AssetSymbol, request.Blockchain, address));

                await _addressDataWriter.CleanAndKeepMaxPartitions(Program.Settings.MaxClientInCache);

                _logger.LogInformation("Handle GetDepositAddress, request: {jsonText}, address: {address}",
                                       JsonConvert.SerializeObject(request), address);

                return(new GetDepositAddressResponse
                {
                    Address = address,
                    Error = GetDepositAddressResponse.ErrorCode.Ok
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception on GetDepositAddress with request: {jsonText}",
                                 JsonConvert.SerializeObject(request));
                throw;
            }
        }
        private async Task DoTime()
        {
            var maxCount = Program.ReloadedSettings(e => e.PreGeneratedAddressesCount).Invoke();
            var wallets  = await _bitGoAssetMapSettingsService.GetAllAssetMapsAsync();

            foreach (var wallet in wallets)
            {
                var assetIdentity = new AssetIdentity
                {
                    BrokerId = wallet.BrokerId,
                    Symbol   = wallet.AssetSymbol
                };

                var paymentSettings = _assetPaymentSettingsClient.GetAssetById(assetIdentity);
                if (paymentSettings?.BitGoCrypto?.IsEnabledDeposit != true)
                {
                    continue;
                }

                var asset = _assetsDictionaryClient.GetAssetById(assetIdentity);

                if (asset == null || !asset.IsEnabled)
                {
                    continue;
                }

                var blockchain = asset.DepositBlockchains.FirstOrDefault();
                if (string.IsNullOrEmpty(blockchain))
                {
                    continue;
                }

                var entitiesCount = await _dataWriter.GetCountAsync(
                    GeneratedDepositAddressEntity.GeneratePartitionKey(wallet.BrokerId, wallet.BitgoCoin,
                                                                       wallet.BitgoWalletId, blockchain));

                if (entitiesCount < maxCount)
                {
                    for (var i = 1; i <= maxCount - entitiesCount; i++)
                    {
                        try
                        {
                            var id    = Guid.NewGuid().ToString();
                            var label = $"PreGenerated-{id}";
                            var(addressId, address, error) =
                                await _depositAddressGeneratorService.GenerateOrGetAddressIdAsync(wallet.BitgoCoin,
                                                                                                  wallet.BitgoWalletId, label);

                            if (string.IsNullOrEmpty(addressId) || error != null)
                            {
                                _logger.LogError(
                                    "Unable to pre-generate address for broker {broker}, asset {asset}, wallet id {walletId}: {error}",
                                    wallet.BrokerId, wallet.BitgoCoin, wallet.BitgoWalletId, error);
                                continue;
                            }

                            await _dataWriter.InsertAsync(GeneratedDepositAddressEntity.Create(
                                                              new GeneratedDepositAddress
                            {
                                BrokerId             = wallet.BrokerId,
                                Asset                = wallet.BitgoCoin,
                                WalletId             = wallet.BitgoWalletId,
                                PreGeneratedWalletId = id,
                                AddressLabel         = label,
                                Address              = address,
                                BitGoAddressId       = addressId,
                                Blockchain           = blockchain
                            }));
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex,
                                             "Unable to pre-generate address for broker {broker}, asset {asset}, wallet id {walletId}, blockchain {blockchain}",
                                             wallet.BrokerId, wallet.BitgoCoin, wallet.BitgoWalletId, blockchain);
                        }
                    }

                    _logger.LogInformation(
                        "Pre-generated {count} addresses for broker {broker}, asset {asset}, wallet id {walletId}, blockchain {blockchain}",
                        maxCount - entitiesCount, wallet.BrokerId, wallet.BitgoCoin, wallet.BitgoWalletId, blockchain);
                }
            }
        }