예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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
            });
        }
예제 #6
0
 /// <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));
 }