public async Task <IWriterResult> DelistCurrency(string adminUserId, UpdateListingStatusModel model)
        {
            model.ListingStatus = CurrencyListingStatus.Delisted;
            var writerResult = await UpdateListingStatus(adminUserId, model);

            if (!writerResult.Success)
            {
                return(writerResult);
            }

            using (var context = ExchangeDataContextFactory.CreateContext())
            {
                // Checks for closing trade pairs only as it's expected to be in 'delisting' before it's delisted.
                var tradePairs = await context.TradePair.Where(t => t.Status == TradePairStatus.Closing && (t.CurrencyId1 == model.CurrencyId || t.CurrencyId2 == model.CurrencyId)).ToListNoLockAsync();

                foreach (var tradePair in tradePairs)
                {
                    tradePair.Status = TradePairStatus.Closed;
                }

                using (var adminContext = DataContextFactory.CreateContext())
                {
                    adminContext.LogActivity(adminUserId, $"Delisted Currency: {model.Name}");
                    await adminContext.SaveChangesAsync().ConfigureAwait(false);
                }

                await context.SaveChangesAsync().ConfigureAwait(false);

                await CacheService.InvalidateAsync(CacheKey.Currencies(), CacheKey.CurrencyInfo(), CacheKey.CurrencyDataTable(), CacheKey.CurrencySummary(model.CurrencyId)).ConfigureAwait(false);
            }

            writerResult.Message = "Successfully delisted currency.";

            return(writerResult);
        }
예제 #2
0
        private async Task ProcessInternal(DateTime startOfMonthToProcess)
        {
            Log.Message(LogLevel.Info, $"[Process] - CEFS processing round {startOfMonthToProcess.Date} started.");
            List <string>             transactionIds = new List <string>();
            Dictionary <int, decimal> tradeHistoryFeeByCurrencyTotals    = new Dictionary <int, decimal>();
            Dictionary <int, decimal> paytopiaPaymentFeeByCurrencyTotals = new Dictionary <int, decimal>();
            Dictionary <int, decimal> tradeHistoryPortionsOfCurrency     = new Dictionary <int, decimal>();
            Dictionary <int, decimal> paytopiaPaymentPortionsOfCurrency  = new Dictionary <int, decimal>();

            using (var context = ExchangeDataContextFactory.CreateContext())
            {
                // get users and balances for each user
                var userIdsAndBalances = await GetUsersAndTheirBalanacesForCEFPayments(startOfMonthToProcess, context);

                // if we have some users, do the CEFS processing routine.
                if (userIdsAndBalances.Any())
                {
                    await CalculateFeeTotalsAndPortions(startOfMonthToProcess, tradeHistoryFeeByCurrencyTotals, paytopiaPaymentFeeByCurrencyTotals, tradeHistoryPortionsOfCurrency, paytopiaPaymentPortionsOfCurrency);

                    TransferSumsToSystemStagingUser(transactionIds, tradeHistoryFeeByCurrencyTotals, paytopiaPaymentFeeByCurrencyTotals, context);
                    List <int> Currencies = GetDistinctCurrencyIds(tradeHistoryPortionsOfCurrency, paytopiaPaymentPortionsOfCurrency);

                    List <TransferHistory> transfers = CreateTransferHistoriesForUsersToReceiveCEFSPayments(tradeHistoryPortionsOfCurrency, paytopiaPaymentPortionsOfCurrency, userIdsAndBalances);

                    Log.Message(LogLevel.Info, "Committing CEFS calculations to database.");
                    await SaveTransfersAndAuditAllUserBalances(userIdsAndBalances, transfers, Currencies, context);
                    await PerformWalletTransactionsAndUpdateDepositsWithIds(transactionIds, context);
                }
            }

            Log.Message(LogLevel.Info, "CEFS Processing round complete.");
        }
예제 #3
0
        public async Task <IWriterResult> AddUserToTransaction(string adminUserId, UpdateNzdtTransactionModel model)
        {
            int transactionId;

            using (var context = ExchangeDataContextFactory.CreateContext())
            {
                var transaction = await context.NzdtTransaction.FirstOrDefaultNoLockAsync(x => x.Id == model.TransactionId).ConfigureAwait(false);

                if (transaction == null)
                {
                    return(new WriterResult(false, "Transaction not Found"));
                }
                else if (transaction.TransactionStatus != Enums.NzdtTransactionStatus.ErrorUserNotFound)
                {
                    return(new WriterResult(false, "Transaction not in ErrorUserNotFound Status"));
                }

                var user = await context.Users.FirstOrDefaultNoLockAsync(x => x.UserName == model.UserName).ConfigureAwait(false);

                if (user == null)
                {
                    return(new WriterResult(false, "User not Found"));
                }
                else if (user.VerificationLevel != Enums.VerificationLevel.Level2 && user.VerificationLevel != Enums.VerificationLevel.Level3)
                {
                    return(new WriterResult(false, "User Verification level is not Level2 or Level3"));
                }

                transactionId = transaction.Id;

                transaction.User = user;
                transaction.TransactionStatus = Enums.NzdtTransactionStatus.ReadyForProcessing;

                await context.SaveChangesAsync().ConfigureAwait(false);
            }

            using (var context = HubDataContextFactory.CreateContext())
            {
                var logMessage = $"[NZDT Import] Added User To Transaction with Id {transactionId}";

                context.LogActivity(adminUserId, logMessage);
                await context.SaveChangesAsync().ConfigureAwait(false);
            }

            return(new WriterResult(true, "User Added to Transaction"));
        }
        public async Task <IWriterResult> UpdateCurrency(string adminUserId, UpdateCurrencyModel model)
        {
            try
            {
                using (var context = ExchangeDataContextFactory.CreateContext())
                {
                    var currency =
                        await context.Currency.Where(c => c.Id == model.Id).FirstOrDefaultNoLockAsync().ConfigureAwait(false);

                    if (currency == null)
                    {
                        return(new WriterResult(false, "Currency not found"));
                    }

                    currency.PoolFee          = model.PoolFee;
                    currency.TradeFee         = model.TradeFee;
                    currency.WithdrawFee      = model.WithdrawFee;
                    currency.WithdrawFeeType  = model.WithdrawFeeType;
                    currency.MinWithdraw      = model.WithdrawMin;
                    currency.MaxWithdraw      = model.WithdrawMax;
                    currency.MinTip           = model.TipMin;
                    currency.MinBaseTrade     = model.MinBaseTrade;
                    currency.MinConfirmations = model.MinConfirmations;
                    currency.Status           = model.Status;
                    currency.StatusMessage    = model.StatusMessage;
                    currency.ListingStatus    = model.ListingStatus;

                    using (var adminContext = DataContextFactory.CreateContext())
                    {
                        adminContext.LogActivity(adminUserId, $"Updated Currency: {currency.Symbol}");
                    }

                    await context.SaveChangesAsync().ConfigureAwait(false);

                    await CacheService.InvalidateAsync(CacheKey.Currencies(), CacheKey.CurrencyInfo(), CacheKey.CurrencyDataTable(), CacheKey.CurrencySummary(model.Id)).ConfigureAwait(false);

                    return(new WriterResult(true, "Succesfully updated currency settings."));
                }
            }
            catch (Exception)
            {
                return(null);
            }
        }
        private async Task <IWriterResult> UpdateListingStatus(string adminUserId, UpdateListingStatusModel model)
        {
            try
            {
                using (var context = ExchangeDataContextFactory.CreateContext())
                {
                    var currency =
                        await context.Currency.Where(c => c.Id == model.CurrencyId).FirstOrDefaultNoLockAsync().ConfigureAwait(false);

                    if (currency == null)
                    {
                        return(new WriterResult(false, "Currency not found"));
                    }

                    var oldStatus = currency.ListingStatus;
                    currency.StatusMessage     = model.StatusMessage;
                    currency.ListingStatus     = model.ListingStatus;
                    currency.Settings.DelistOn = model.DelistOn;

                    using (var adminContext = DataContextFactory.CreateContext())
                    {
                        adminContext.LogActivity(adminUserId, $"Updated Currency listing status from : {oldStatus} to: {model.ListingStatus}");
                        await adminContext.SaveChangesAsync().ConfigureAwait(false);
                    }

                    await context.SaveChangesAsync().ConfigureAwait(false);

                    await CacheService.InvalidateAsync(CacheKey.Currencies(), CacheKey.CurrencyInfo(), CacheKey.CurrencyDataTable(), CacheKey.CurrencySummary(model.CurrencyId)).ConfigureAwait(false);

                    return(new WriterResult(true, "Succesfully updated listing status."));
                }
            }
            catch (Exception)
            {
                return(null);
            }
        }
예제 #6
0
        public async Task <IServiceResult <NzdtUploadResultModel> > ValidateAndUpload(string adminUserId, Stream inputStream)
        {
            var processResult = await ProcessCsv(inputStream);

            if (!processResult.Success || !processResult.HasResult)
            {
                return(new ServiceResult <NzdtUploadResultModel>(false, processResult.Message));
            }

            var csvTransactionItems = processResult.Result;
            var firstDate           = csvTransactionItems.Min(x => x.Date);

            var resultModel = new NzdtUploadResultModel
            {
                TotalCount = csvTransactionItems.Count
            };

            List <NzdtTransaction> transactionsToUpload = new List <NzdtTransaction>();

            long firstUploadedTransactionUniqueId = 0;
            long lastUploadedTransactionUniqueId  = 0;

            using (var context = ExchangeDataContextFactory.CreateContext())
            {
                var transactions = await context.NzdtTransaction
                                   .Where(t => t.Date >= firstDate)
                                   .ToListNoLockAsync().ConfigureAwait(false);

                var addressProjections = await context.Address
                                         .Where(a => a.CurrencyId == Constant.NZDT_ID)
                                         .Select(a => new AddressProjection
                {
                    UserId            = a.UserId,
                    UserName          = a.User.UserName,
                    VerificationLevel = a.User.VerificationLevel,
                    AddressHash       = a.AddressHash,
                }).ToListNoLockAsync().ConfigureAwait(false);

                foreach (var item in csvTransactionItems)
                {
                    var matchingTransaction = transactions.FirstOrDefault(x => x.UniqueId == item.UniqueId);
                    var matchingAddress     = addressProjections.FirstOrDefault(x => item.Memo.ToUpper().Contains(x.Address));

                    if (matchingTransaction != null)
                    {
                        //Transaction Exists
                        resultModel.ExistingCount++;
                        continue;
                    }

                    if (matchingAddress != null)
                    {
                        var isVerificationValid = (matchingAddress.VerificationLevel == VerificationLevel.Level2 || matchingAddress.VerificationLevel == VerificationLevel.Level3);

                        if (isVerificationValid)
                        {
                            transactionsToUpload.Add(new NzdtTransaction
                            {
                                TransactionStatus = NzdtTransactionStatus.ReadyForProcessing,
                                UserId            = matchingAddress.UserId,

                                Date         = item.Date,
                                UniqueId     = item.UniqueId,
                                TranType     = item.TranType,
                                ChequeNumber = item.ChequeNumber,
                                Payee        = item.Payee,
                                Memo         = item.Memo,
                                Amount       = item.Amount,

                                CreatedOn = DateTime.UtcNow
                            });

                            resultModel.ReadyForProcessingCount++;
                        }
                        else
                        {
                            transactionsToUpload.Add(new NzdtTransaction
                            {
                                TransactionStatus = NzdtTransactionStatus.ErrorUserNotVerified,
                                UserId            = matchingAddress.UserId,

                                Date         = item.Date,
                                UniqueId     = item.UniqueId,
                                TranType     = item.TranType,
                                ChequeNumber = item.ChequeNumber,
                                Payee        = item.Payee,
                                Memo         = item.Memo,
                                Amount       = item.Amount,

                                CreatedOn = DateTime.UtcNow
                            });

                            resultModel.ErroredCount++;
                        }
                    }
                    else
                    {
                        transactionsToUpload.Add(new NzdtTransaction
                        {
                            TransactionStatus = NzdtTransactionStatus.ErrorUserNotFound,

                            Date         = item.Date,
                            UniqueId     = item.UniqueId,
                            TranType     = item.TranType,
                            ChequeNumber = item.ChequeNumber,
                            Payee        = item.Payee,
                            Memo         = item.Memo,
                            Amount       = item.Amount,

                            CreatedOn = DateTime.UtcNow
                        });

                        resultModel.ErroredCount++;
                    }
                }

                if (resultModel.TotalCount != (resultModel.ExistingCount + resultModel.ReadyForProcessingCount + resultModel.ErroredCount))
                {
                    return(new ServiceResult <NzdtUploadResultModel>(false, "Error. Processed Transaction Count was out from Total Count"));
                }

                if (transactionsToUpload.Any())
                {
                    firstUploadedTransactionUniqueId = transactionsToUpload.First().UniqueId;
                    lastUploadedTransactionUniqueId  = transactionsToUpload.Last().UniqueId;
                }

                context.NzdtTransaction.AddRange(transactionsToUpload);
                await context.SaveChangesAsync().ConfigureAwait(false);
            }

            using (var context = HubDataContextFactory.CreateContext())
            {
                var logMessage = $"[NZDT Import] Imported {resultModel.ReadyForProcessingCount}. ";

                if (resultModel.ReadyForProcessingCount > 0)
                {
                    logMessage += $"UniqueIds between {firstUploadedTransactionUniqueId} and {lastUploadedTransactionUniqueId}";
                }

                context.LogActivity(adminUserId, logMessage);
                await context.SaveChangesAsync().ConfigureAwait(false);
            }

            return(new ServiceResult <NzdtUploadResultModel>(true, resultModel));
        }
        public async Task <IWriterResult> BeginDelistingCurrency(string adminUserId, UpdateListingStatusModel model)
        {
            model.ListingStatus = CurrencyListingStatus.Delisting;

            if (model.DelistOn == null)
            {
                return(new WriterResult(false, "Delist date cannot be null"));
            }

            var writerResult = await UpdateListingStatus(adminUserId, model);

            if (!writerResult.Success)
            {
                return(writerResult);
            }

            using (var context = ExchangeDataContextFactory.CreateContext())
            {
                // Checks for open trade pairs only to avoid accidentally relisting delisted currencies.
                var tradePairs = await context.TradePair.Where(t => (t.Status == TradePairStatus.OK || t.Status == TradePairStatus.Paused) && (t.CurrencyId1 == model.CurrencyId || t.CurrencyId2 == model.CurrencyId)).ToListNoLockAsync();

                foreach (var tradePair in tradePairs)
                {
                    tradePair.Status = TradePairStatus.Closing;
                }

                using (var adminContext = DataContextFactory.CreateContext())
                {
                    adminContext.LogActivity(adminUserId, "Closing TradePair due to delisting");
                    await adminContext.SaveChangesAsync().ConfigureAwait(false);
                }

                await context.SaveChangesAsync().ConfigureAwait(false);

                await CacheService.InvalidateAsync(CacheKey.AllTradePairs(), CacheKey.TradePairs()).ConfigureAwait(false);
            }

            writerResult.Message = "Successfully started the delisting process.";

            try
            {
                var email = new EmailMessageModel
                {
                    EmailType        = EmailTemplateType.CoinDelisting,
                    BodyParameters   = new object[0],
                    SystemIdentifier = model.Symbol
                };

                using (var context = ExchangeDataContextFactory.CreateReadOnlyContext())
                {
                    var balances = await context.Balance.Include(b => b.User).Where(b => b.Currency.Name == model.Name && b.Total > 0).OrderBy(b => b.User.Email).ToListNoLockAsync();

                    if (!balances.Any())
                    {
                        writerResult.Message = "Successfully started the delisting process but no non zero balances found so no emails were sent.";
                        return(writerResult);
                    }

                    var personalisations = new List <IEmailPersonalisation>(balances.Select(balance => new EmailPersonalisation {
                        Tos = new List <string> {
                            balance.User.Email
                        },
                        Substitutions = new Dictionary <string, string>
                        {
                            { "-name-", balance.User.UserName },
                            { "-coinName-", model.Name },
                            { "-coinSymbol-", model.Symbol },
                            { "-delistDate-", model.DelistOn.Value.ToString("R") },
                            { "-delistReason-", model.StatusMessage },
                            { "-balance-", balance.Total.ToString(CultureInfo.InvariantCulture) }
                        }
                    })
                                                                            .ToList());

                    var hasSentSuccessfully = await EmailService.SendEmails(email, personalisations);

                    if (!hasSentSuccessfully)
                    {
                        writerResult.Success = false;
                        writerResult.Message = "Successfully started the delisting process but emails failed to send.";
                        return(writerResult);
                    }
                }

                using (var adminContext = DataContextFactory.CreateContext())
                {
                    adminContext.LogActivity(adminUserId, $"Started Currency Delisting Process for: {model.Name}");
                    await adminContext.SaveChangesAsync().ConfigureAwait(false);
                }
            }
            catch (Exception)
            {
                return(new WriterResult(false, "Sending emails failed"));
            }
            return(writerResult);
        }
예제 #8
0
        private async Task ProcessTransactions()
        {
            Log.Message(LogLevel.Info, "[ProcessNZDT] - Processing NZDT Transactions...");

            List <NzdtTransaction> nzdtTransactions;

            using (var context = ExchangeDataContextFactory.CreateContext())
            {
                nzdtTransactions = await context.NzdtTransaction
                                   .Where(x => x.TransactionStatus == NzdtTransactionStatus.ReadyForProcessing)
                                   .Where(x => DbFunctions.AddHours(x.CreatedOn, 1) <= DateTime.UtcNow)
                                   .ToListNoLockAsync();

                Log.Message(LogLevel.Info, $"[ProcessNZDT] - {nzdtTransactions.Count()} transactions found, processing...");

                foreach (var transaction in nzdtTransactions)
                {
                    transaction.TransactionStatus = NzdtTransactionStatus.Processed;
                }

                await context.SaveChangesAsync();
            }

            var wallet = new WalletConnector(_nzdtAssetWalletIp, _nzdtAssetWalletPort, _nzdtAssetWalletUserName, _nzdtAssetWalletPassword, 30000);

            foreach (var transaction in nzdtTransactions)
            {
                try
                {
                    var sendResult = await wallet.SendToAddressAsync(Constant.NzdtBaseExchangeAddress, transaction.Amount);

                    using (var context = ExchangeDataContextFactory.CreateContext())
                    {
                        var deposit = new Deposit
                        {
                            Txid          = string.IsNullOrEmpty(sendResult?.Txid) ? $"{transaction.Id}" : sendResult.Txid,
                            Amount        = transaction.Amount,
                            TimeStamp     = DateTime.UtcNow,
                            CurrencyId    = Constant.NZDT_ID,
                            Status        = DepositStatus.Confirmed,
                            Confirmations = 20,
                            UserId        = transaction.UserId.Value,
                            Type          = DepositType.Normal
                        };

                        var tx = await context.NzdtTransaction.FirstNoLockAsync(x => x.Id == transaction.Id);

                        tx.Deposit = deposit;

                        await context.SaveChangesAsync();

                        await context.AuditUserBalance(transaction.UserId.Value, Constant.NZDT_ID);

                        await context.SaveChangesAsync();
                    }
                }
                catch (Exception ex)
                {
                    Log.Exception($"[ProcessNZDT] Insert Deposit failed for transaction {transaction.Id}", ex);
                }
            }

            Log.Message(LogLevel.Info, $"[ProcessNZDT] - Processing NZDT Transactions complete.");
        }
        public async Task ProcessExchanges()
        {
            using (var context = ExchangeDataContextFactory.CreateContext())
            {
                Log.Message(LogLevel.Info, "[ProcessExchanges] - Creating tradepair map...");
                var tradePairs = await context.TradePair
                                 .Where(x => x.Status == TradePairStatus.OK || x.Status == TradePairStatus.Paused)
                                 .Select(t => new
                {
                    TradePairId = t.Id,
                    Symbol      = t.Currency1.Symbol,
                    BaseSymbol  = t.Currency2.Symbol
                }).ToListNoLockAsync();

                if (tradePairs.IsNullOrEmpty())
                {
                    return;
                }
                var tradePairMap = tradePairs.ToDictionary(k => string.Format("{0}_{1}", k.Symbol, k.BaseSymbol), v => v.TradePairId);
                Log.Message(LogLevel.Info, "[ProcessExchanges] - Tradepair map created.");

                Log.Message(LogLevel.Info, "[ProcessExchanges] - Processing exchanges...");
                foreach (var exchange in _exchanges)
                {
                    if (!_isEnabled)
                    {
                        break;
                    }

                    try
                    {
                        Log.Message(LogLevel.Info, "[ProcessExchanges] - Processing exchange. Exchange: {0}", exchange.Name);
                        var existingData =
                            await context.IntegrationMarketData.Where(x => x.IntegrationExchangeId == exchange.Id).ToListNoLockAsync();

                        var marketData = await exchange.GetMarketData(tradePairMap);

                        if (!marketData.IsNullOrEmpty())
                        {
                            Log.Message(LogLevel.Info, "[ProcessExchanges] - Market data found, Updating database");
                            foreach (var data in marketData)
                            {
                                if (!_isEnabled)
                                {
                                    break;
                                }

                                if (tradePairMap.ContainsKey(data.TradePair))
                                {
                                    var existing = existingData.FirstOrDefault(x => x.TradePairId == tradePairMap[data.TradePair]);
                                    if (existing == null)
                                    {
                                        existing = new IntegrationMarketData
                                        {
                                            IntegrationExchangeId = exchange.Id,
                                            TradePairId           = tradePairMap[data.TradePair]
                                        };
                                        context.IntegrationMarketData.Add(existing);
                                    }

                                    existing.Timestamp  = DateTime.UtcNow;
                                    existing.Ask        = data.Ask;
                                    existing.Bid        = data.Bid;
                                    existing.Last       = data.Last;
                                    existing.Volume     = data.Volume;
                                    existing.BaseVolume = data.BaseVolume;
                                    existing.MarketUrl  = data.MarketUrl;
                                }
                            }
                            await context.SaveChangesAsync();

                            Log.Message(LogLevel.Info, "[ProcessExchanges] - Market data updated.");
                        }

                        var expiredData = existingData.Where(x => x.Timestamp.AddMinutes(_expirePeriod) < DateTime.UtcNow);
                        if (expiredData.Any())
                        {
                            Log.Message(LogLevel.Info, "[ProcessExchanges] - Expired data found, Deleteing...");
                            foreach (var expired in expiredData)
                            {
                                if (!_isEnabled)
                                {
                                    break;
                                }

                                context.IntegrationMarketData.Remove(expired);
                            }
                            await context.SaveChangesAsync();

                            Log.Message(LogLevel.Info, "[ProcessExchanges] - Expired data deleted.");
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Exception("[ProcessExchanges] - An exception occured processing exchange, Exchange: {0}", ex, exchange.Name);
                    }
                }
                Log.Message(LogLevel.Info, "[ProcessExchanges] - Processing exchanges complete.");
            }
        }
예제 #10
0
        private async Task ProcessPaytopiaItems()
        {
            try
            {
                var now            = DateTime.UtcNow;
                var beginingOfWeek = now.StartOfWeek(DayOfWeek.Monday);
                var endOfWeek      = beginingOfWeek.AddDays(7);
                var featuredItems  = new List <FeaturedInfo>();
                using (var context = DataContextFactory.CreateContext())
                {
                    featuredItems = await context.PaytopiaPayments
                                    .Where(x => x.Begins >= beginingOfWeek && x.Ends <= endOfWeek && (x.PaytopiaItem.Type == PaytopiaItemType.FeaturedCurrency || x.PaytopiaItem.Type == PaytopiaItemType.FeaturedPool))
                                    .Select(x => new FeaturedInfo
                    {
                        Id         = x.ReferenceId,
                        Type       = x.PaytopiaItem.Type,
                        ExpireTime = x.Ends
                    }).ToListNoLockAsync();
                }

                if (!featuredItems.Any())
                {
                    return;
                }

                // update currencies
                using (var context = ExchangeDataContextFactory.CreateContext())
                {
                    var currencyIds = featuredItems.Where(x => x.Type == PaytopiaItemType.FeaturedCurrency).Select(x => x.Id).ToList();
                    var currencies  = await context.Currency.Where(x => currencyIds.Contains(x.Id)).ToListNoLockAsync();

                    foreach (var currency in currencies)
                    {
                        var featureExpireTime = featuredItems.First(x => x.Type == PaytopiaItemType.FeaturedCurrency && x.Id == currency.Id).ExpireTime;
                        if (featureExpireTime != currency.FeaturedExpires)
                        {
                            currency.FeaturedExpires = featureExpireTime;
                        }
                    }
                    await context.SaveChangesAsync();
                }

                // update pools
                using (var context = PoolDataContextFactory.CreateContext())
                {
                    var poolIds = featuredItems.Where(x => x.Type == PaytopiaItemType.FeaturedPool).Select(x => x.Id).ToList();
                    var pools   = await context.Pool.Where(x => poolIds.Contains(x.Id)).ToListNoLockAsync();

                    foreach (var pool in pools)
                    {
                        var featureExpireTime = featuredItems.First(x => x.Type == PaytopiaItemType.FeaturedPool && x.Id == pool.Id).ExpireTime;
                        if (featureExpireTime != pool.FeaturedExpires)
                        {
                            pool.FeaturedExpires = featureExpireTime;
                        }
                    }
                    await context.SaveChangesAsync();
                }
            }
            catch (Exception ex)
            {
                Log.Exception("[ProcessPaytopiaItems] - An exception occurred processing Paytopia items.", ex);
            }
        }
예제 #11
0
        /// <summary>
        /// Processes the lotto items.
        /// </summary>
        private async Task ProcessLotto()
        {
            try
            {
                var payouts = new List <PrizePayout>();
                using (var context = ExchangeDataContextFactory.CreateContext())
                {
                    Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItems...");
                    var dueLottoDraws = await context.LottoItem.Where(x => x.Status != LottoItemStatus.Disabled && DateTime.UtcNow >= x.NextDraw).ToListNoLockAsync();

                    if (dueLottoDraws.IsNullOrEmpty())
                    {
                        // no draws ready
                        Log.Message(LogLevel.Info, "[ProcessLotto] - No lotto draws are due, Waiting...");
                        return;
                    }

                    Log.Message(LogLevel.Info, "[ProcessLotto] - {0} lotto draws found.", dueLottoDraws.Count());
                    foreach (var lottoDraw in dueLottoDraws)
                    {
                        Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItem, Id: {0}, Name: {1}, Currency: {2}", lottoDraw.Id, lottoDraw.Name, lottoDraw.CurrencyId);
                        // 1. sum up total tickets, subtract site fee
                        var tickets = await context.LottoTicket.Where(x => !x.IsArchived && x.LottoItemId == lottoDraw.Id && x.DrawId == lottoDraw.CurrentDrawId).ToListNoLockAsync();

                        if (!tickets.IsNullOrEmpty())
                        {
                            Log.Message(LogLevel.Info, "[ProcessLotto] - {0} tickets found for draw.", tickets.Count());
                            // Archive all the tickets
                            foreach (var ticket in tickets)
                            {
                                ticket.IsArchived = true;
                            }

                            // Calculate prize pool
                            var totalAmount       = lottoDraw.Rate * tickets.Count();
                            var siteFee           = (totalAmount / 100m) * lottoDraw.Fee;
                            var prizePool         = totalAmount - siteFee;
                            var prizePoolFraction = prizePool / 100m;
                            var prizeWeights      = LottoHelpers.GetPrizeWeights(lottoDraw.Prizes);
                            var winningTicketIds  = GetWinningLottoItemIds(tickets.Select(x => x.Id), lottoDraw.Prizes);
                            Log.Message(LogLevel.Info, "[ProcessLotto] - LottoItem draw info, Total: {0}, PrizePool: {1}, Fee: {2}", totalAmount, prizePool, siteFee);

                            // Calculate user prizes
                            var drawTime = lottoDraw.NextDraw;
                            for (int i = 0; i < prizeWeights.Count; i++)
                            {
                                var prizeWeight   = prizeWeights[i];
                                var winningTicket = tickets.FirstOrDefault(x => x.Id == winningTicketIds[i]);
                                var amount        = Math.Round(prizePoolFraction * prizeWeight, 8);
                                payouts.Add(new PrizePayout
                                {
                                    UserId     = winningTicket.UserId,
                                    CurrencyId = lottoDraw.CurrencyId,
                                    Amount     = amount
                                });
                                context.LottoHistory.Add(new LottoHistory
                                {
                                    Amount        = amount,
                                    Percent       = prizeWeight,
                                    LottoItemId   = lottoDraw.Id,
                                    Position      = (i + 1),
                                    Timestamp     = drawTime,
                                    UserId        = winningTicket.UserId,
                                    LottoTicketId = winningTicket.Id,
                                    LottoDrawId   = lottoDraw.CurrentDrawId,
                                    TotalAmount   = prizePool
                                });
                                Log.Message(LogLevel.Info, "[ProcessLotto] - User payout info, UserId: {0}, Position: {1}, Weight: {2}, Amount: {3}", winningTicket.UserId, (i + 1), prizeWeight, amount);
                            }
                        }
                        else
                        {
                            Log.Message(LogLevel.Info, "[ProcessLotto] - No tickets found for draw.");
                        }

                        // 5. update LottoItem
                        lottoDraw.Status = LottoItemStatus.Finished;
                        if (lottoDraw.LottoType == LottoType.Recurring || (lottoDraw.LottoType == LottoType.RecurringExpire && lottoDraw.Expires > DateTime.UtcNow))
                        {
                            lottoDraw.Status        = LottoItemStatus.Active;
                            lottoDraw.CurrentDrawId = lottoDraw.CurrentDrawId + 1;
                            lottoDraw.NextDraw      = lottoDraw.NextDraw.AddHours(lottoDraw.Hours);
                            Log.Message(LogLevel.Info, "[ProcessLotto] - Set next draw date for recurring lotto, NextDraw: {0}", lottoDraw.NextDraw);
                        }

                        Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItem complete.");
                    }

                    // commit the transaction
                    Log.Message(LogLevel.Debug, "[ProcessLotto] - Comitting database transaction...");
                    await context.SaveChangesAsync();

                    Log.Message(LogLevel.Debug, "[ProcessLotto] - Comitted database transaction.");
                }

                // Send Winnings
                await PayoutUsers(payouts);

                Log.Message(LogLevel.Info, "[ProcessLotto] - Processing LottoItems complete.");
            }
            catch (Exception ex)
            {
                Log.Exception("[ProcessLotto] - An exception occured processing LottoItem.", ex);
            }
        }