private List <LottoPrizeInfoModel> GetPrizeInfo(LottoItemModel lottoItem) { var prizeInfo = new List <LottoPrizeInfoModel>(); var totalAmount = lottoItem.Rate * lottoItem.TicketsInDraw; var siteFee = (totalAmount / 100m) * lottoItem.Fee; var prizePool = totalAmount - siteFee; var prizePoolFraction = prizePool / 100m; var prizeWeights = LottoHelpers.GetPrizeWeights(lottoItem.Prizes); for (int i = 0; i < prizeWeights.Count; i++) { prizeInfo.Add(new LottoPrizeInfoModel { Percentage = prizeWeights[i], Position = (i + 1), Prize = Math.Round(prizePoolFraction * prizeWeights[i], 8) }); } return(prizeInfo); }
/// <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); } }