private async Task ProcessMessageAsync(CashInEvent item) { if (!_depositCurrencies.Contains(item.CashIn.AssetId, StringComparer.InvariantCultureIgnoreCase)) { return; } _log.Info("CashIn event", context: item.ToJson()); double volume = Convert.ToDouble(item.CashIn.Volume); (double convertedVolume, string assetId) = await _currencyConverter.ConvertAsync(item.CashIn.AssetId, volume); if (convertedVolume == 0) { return; } _cqrsEngine.PublishEvent(new ClientDepositedEvent { ClientId = item.CashIn.WalletId, OperationId = item.Header.MessageId ?? item.Header.RequestId, Asset = item.CashIn.AssetId, Amount = volume, BaseAsset = assetId, BaseVolume = convertedVolume, OperationType = "CashIn", Timestamp = item.Header.Timestamp }, TierBoundedContext.Name); }
public virtual async Task AddDataItemAsync(T item) { var converted = await _currencyConverter.ConvertAsync(item.Asset, _currencyConverter.DefaultAsset, item.Volume, true); item.BaseAsset = converted.Item1; item.BaseVolume = converted.Item2; item.OperationType = GetOperationType(item); bool isNewItem = await _data.AddDataItemAsync(item); if (isNewItem) { await _antiFraudCollector.RemoveOperationAsync( item.ClientId, item.Asset, item.Volume, item.OperationType.Value); } }
private async Task ProcessMessageAsync(CashTransferEvent item) { if (!_depositCurrencies.Contains(item.CashTransfer.AssetId, StringComparer.InvariantCultureIgnoreCase)) { return; } var transfer = item.CashTransfer; if (await IsTransferBetweenClientWalletsAsync(transfer.FromWalletId, transfer.ToWalletId)) { _log.Info("Skip transfer between client wallets", context: item.ToJson()); return; } double volume = Convert.ToDouble(transfer.Volume); (double convertedVolume, string assetId) = await _currencyConverter.ConvertAsync(transfer.AssetId, volume); if (convertedVolume == 0) { return; } string operationType = GetOperationType(item.CashTransfer); _cqrsEngine.PublishEvent(new ClientDepositedEvent { ClientId = transfer.ToWalletId, FromClientId = transfer.FromWalletId, OperationId = item.Header.MessageId ?? item.Header.RequestId, Asset = transfer.AssetId, Amount = volume, BaseAsset = assetId, BaseVolume = convertedVolume, OperationType = operationType, Timestamp = item.Header.Timestamp }, TierBoundedContext.Name); }
public async Task <double> GetAttemptsValueAsync( string clientId, string asset, LimitationType limitType) { var keys = await GetClientAttemptKeysAsync(clientId); if (keys.Length == 0) { return(0); } var attemptJsons = await _db.StringGetAsync(keys); var opTypes = LimitMapHelper.MapLimitationType(limitType); var attempts = attemptJsons .Where(a => a.HasValue) .Select(a => a.ToString().DeserializeJson <CurrencyOperationAttempt>()) .Where(a => opTypes.Contains(a.OperationType)) .ToList(); double result = 0; foreach (var attempt in attempts) { if (_currencyConverter.IsNotConvertible(asset) && attempt.Asset == asset) { result += attempt.Amount; } else if (!_currencyConverter.IsNotConvertible(asset) && !_currencyConverter.IsNotConvertible(attempt.Asset)) { var converted = await _currencyConverter.ConvertAsync(attempt.Asset, asset, attempt.Amount); result += converted.Item2; } } return(result); }
public async Task <LimitationCheckResult> CheckCashOperationLimitAsync( string clientId, string assetId, double amount, CurrencyOperationType currencyOperationType) { var originalAsset = assetId; var originalAmount = amount; amount = Math.Abs(amount); if (currencyOperationType == CurrencyOperationType.CryptoCashOut) { var asset = _assets.Get(assetId); if (amount < asset.CashoutMinimalAmount) { var minimalAmount = asset.CashoutMinimalAmount.GetFixedAsString(asset.Accuracy).TrimEnd('0'); return(new LimitationCheckResult { IsValid = false, FailMessage = $"The minimum amount to cash out is {minimalAmount}" }); } if (asset.LowVolumeAmount.HasValue && amount < asset.LowVolumeAmount) { var settings = await _limitSettingsRepository.GetAsync(); var timeout = TimeSpan.FromMinutes(settings.LowCashOutTimeoutMins); var callHistory = await _callTimeLimitsRepository.GetCallHistoryAsync("CashOutOperation", clientId, timeout); var cashoutEnabled = !callHistory.Any() || callHistory.IsCallEnabled(timeout, settings.LowCashOutLimit); if (!cashoutEnabled) { return new LimitationCheckResult { IsValid = false, FailMessage = "You have exceeded cash out operations limit. Please try again later." } } ; } } if (currencyOperationType == CurrencyOperationType.SwiftTransferOut) { var error = await CheckSwiftWithdrawLimitations(assetId, (decimal)amount); if (error != null) { return(new LimitationCheckResult { IsValid = false, FailMessage = error }); } } if (currencyOperationType != CurrencyOperationType.CryptoCashIn && currencyOperationType != CurrencyOperationType.CryptoCashOut) { (assetId, amount) = await _currencyConverter.ConvertAsync( assetId, _currencyConverter.DefaultAsset, amount); } var limitationTypes = LimitMapHelper.MapOperationType(currencyOperationType); var typeLimits = _limits.Where(l => limitationTypes.Contains(l.LimitationType)).ToList(); if (!typeLimits.Any()) { try { await _limitOperationsApi.AddOperationAttemptAsync( clientId, originalAsset, originalAmount, currencyOperationType == CurrencyOperationType.CardCashIn ?CashOperationsTimeoutInMinutes : _attemptRetainInMinutes, currencyOperationType); } catch (Exception ex) { _log.Error(ex, context: new { Type = "Attempt", clientId, originalAmount, originalAsset }); } return(new LimitationCheckResult { IsValid = true }); } //To handle parallel request await _lock.WaitAsync(); try { var assetLimits = typeLimits.Where(l => l.Asset == assetId).ToList(); string error = await DoPeriodCheckAsync( assetLimits, LimitationPeriod.Month, clientId, assetId, amount, currencyOperationType, false); if (error != null) { return new LimitationCheckResult { IsValid = false, FailMessage = error } } ; error = await DoPeriodCheckAsync( assetLimits, LimitationPeriod.Day, clientId, assetId, amount, currencyOperationType, false); if (error != null) { return new LimitationCheckResult { IsValid = false, FailMessage = error } } ; if (currencyOperationType == CurrencyOperationType.CryptoCashOut) { assetLimits = typeLimits.Where(l => l.Asset == _currencyConverter.DefaultAsset).ToList(); var(assetTo, convertedAmount) = await _currencyConverter.ConvertAsync( assetId, _currencyConverter.DefaultAsset, amount, true); error = await DoPeriodCheckAsync( assetLimits, LimitationPeriod.Month, clientId, assetTo, convertedAmount, currencyOperationType, true); if (error != null) { return new LimitationCheckResult { IsValid = false, FailMessage = error } } ; error = await DoPeriodCheckAsync( assetLimits, LimitationPeriod.Day, clientId, assetTo, convertedAmount, currencyOperationType, true); if (error != null) { return new LimitationCheckResult { IsValid = false, FailMessage = error } } ; } try { await _limitOperationsApi.AddOperationAttemptAsync( clientId, originalAsset, originalAmount, currencyOperationType == CurrencyOperationType.CardCashIn ?CashOperationsTimeoutInMinutes : _attemptRetainInMinutes, currencyOperationType); } catch (Exception ex) { _log.Error(ex, context: new { Type = "Attempt", clientId, originalAmount, originalAsset }); } } finally { _lock.Release(); } return(new LimitationCheckResult { IsValid = true }); }
/// <summary> /// Converts the total into specified currency. /// </summary> /// <param name="total">The amount to convert in USD.</param> /// <param name="to">The currency to convert to.</param> /// <returns>The converted amount.</returns> public async Task <decimal> ConvertTotalAsync(decimal total, Currency curTo) { return(curTo == Currency.Usd ? total : await _converter.ConvertAsync(total, Currency.Usd, curTo).ConfigureAwait(false)); }