private async Task <List <ApiTransactionResult> > GetWithdrawals(ApiUserTransactionsRequest request) { var count = Math.Min(request.Count ?? 100, 1000); var cacheResult = await CacheService.GetOrSetHybridAsync(CacheKey.ApiUserTransactions(request.UserId.ToString(), TransactionType.Withdraw), TimeSpan.FromSeconds(60), async() => { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { return(await context.Withdraw .AsNoTracking() .Where(x => x.UserId == request.UserId) .OrderByDescending(x => x.Id) .Take(1000) .Select(x => new ApiTransactionResult { Amount = x.Amount, Confirmations = x.Confirmations, Currency = x.Currency.Symbol, Fee = 0, Id = x.Id, Status = x.Status.ToString(), Timestamp = x.TimeStamp, TxId = x.Txid, Type = "Withdraw", Address = x.Address }).ToListNoLockAsync().ConfigureAwait(false)); } }).ConfigureAwait(false); return(cacheResult); }
public async Task <UserBalanceItemModel> GetBalance(string userId, int currencyId) { try { var currentUser = new Guid(userId); using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var balance = await context.Balance .AsNoTracking() .Where(x => x.UserId == currentUser && x.CurrencyId == currencyId) .Select(x => new UserBalanceItemModel { CurrencyId = x.CurrencyId, HeldForTrades = (decimal?)x.HeldForTrades ?? 0, PendingWithdraw = (decimal?)x.PendingWithdraw ?? 0, Name = x.Currency.Name, Symbol = x.Currency.Symbol, Status = x.Currency.Status, ListingStatus = x.Currency.ListingStatus, StatusMessage = x.Currency.StatusMessage, Total = (decimal?)x.Total ?? 0, Unconfirmed = (decimal?)x.Unconfirmed ?? 0, IsFavorite = (bool?)x.IsFavorite ?? false, CurrencyType = x.Currency.Type, BaseAddress = x.Currency.BaseAddress }).FirstOrDefaultNoLockAsync().ConfigureAwait(false); return(balance); } } catch (Exception) { return(new UserBalanceItemModel()); } }
public async Task <UserBalanceModel> GetBalances(string userId, bool calculateEstimate) { try { var model = new UserBalanceModel(); var currentUser = new Guid(userId); using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var query = from currency in context.Currency from balance in context.Balance.Where(b => b.UserId == currentUser && b.CurrencyId == currency.Id).DefaultIfEmpty() // from address in context.Address.Where(a => a.UserId == currentUser && a.CurrencyId == currency.Id).DefaultIfEmpty() where currency.IsEnabled orderby currency.Name select new UserBalanceItemModel { //Address = address.AddressHash, CurrencyId = currency.Id, HeldForTrades = (decimal?)balance.HeldForTrades ?? 0, PendingWithdraw = (decimal?)balance.PendingWithdraw ?? 0, Name = currency.Name, Symbol = currency.Symbol, Status = currency.Status, ListingStatus = currency.ListingStatus, StatusMessage = currency.StatusMessage, Total = (decimal?)balance.Total ?? 0, Unconfirmed = (decimal?)balance.Unconfirmed ?? 0, IsFavorite = (bool?)balance.IsFavorite ?? false, CurrencyType = currency.Type, BaseAddress = currency.BaseAddress }; var balances = await query.ToListNoLockAsync().ConfigureAwait(false); model.Balances = balances.DistinctBy(x => x.CurrencyId).ToList(); } if (calculateEstimate) { await model.Balances.ForEachAsync(async b => b.EstimatedBTC = await BalanceEstimationService.GetEstimatedBTC(b.Total, b.CurrencyId)); model.BTCEstimate = model.Balances.Sum(x => x.EstimatedBTC); model.BTCEstimateAlt = model.Balances.Where(x => x.CurrencyId != Constant.BITCOIN_ID).Sum(x => x.EstimatedBTC); var verificationData = await UserVerificationReader.GetVerificationStatus(userId).ConfigureAwait(false); model.HasWithdrawLimit = verificationData.Limit > 0; model.WithdrawLimit = verificationData.Limit; model.WithdrawTotal = verificationData.Current; } return(model); } catch (Exception) { return(new UserBalanceModel()); } }
public async Task <DataTablesResponse> GetAddresses(DataTablesModel model) { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var query = context.Address .AsNoTracking() .Select(x => new { Id = x.Id, UserName = x.User.UserName, x.AddressHash }).Distinct(); return(await query.GetDataTableResultNoLockAsync(model).ConfigureAwait(false)); } }
public async Task <UpdateWithdrawalTxModel> GetWithdrawalToUpdate(int id) { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { return(await context.Withdraw .AsNoTracking() .Where(x => x.Status == Enums.WithdrawStatus.Processing) .Select(x => new UpdateWithdrawalTxModel { Id = x.Id, TxId = x.Txid, Status = x.Status, Address = x.Address, Amount = x.Amount, RetryCount = x.RetryCount }).FirstOrDefaultNoLockAsync(x => x.Id == id).ConfigureAwait(false)); } }
public async Task <VerificationStatusModel> GetVerificationStatus(string userId) { var currentUser = new Guid(userId); var lastTime = DateTime.UtcNow.AddHours(-24); using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var user = await context.Users.FirstOrDefaultNoLockAsync(x => x.Id == currentUser); if (user == null) { return(null); } var current = 0m; if (user.VerificationLevel != VerificationLevel.Legacy) { var currentWithdrawDetails = await context.Withdraw .Where(x => x.UserId == currentUser && x.Status != Enums.WithdrawStatus.Canceled && x.TimeStamp > lastTime) .ToListNoLockAsync(); if (currentWithdrawDetails.Any()) { current = currentWithdrawDetails.Sum(x => x.EstimatedPrice); } var currentTransferDetails = await context.Transfer .Where(x => x.UserId == currentUser && x.Timestamp > lastTime && (x.TransferType == TransferType.User || x.TransferType == TransferType.Tip)) .ToListNoLockAsync(); if (currentTransferDetails.Any()) { current += currentTransferDetails.Sum(x => x.EstimatedPrice); } } return(new VerificationStatusModel { Level = user.VerificationLevel, Limit = VerificationLimit(user.VerificationLevel), Current = current }); } }
public async Task <DataTablesResponse> GetTransfers(DataTablesModel model) { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var query = context.Transfer .AsNoTracking() .Select(x => new { Id = x.Id, Sender = x.User.UserName, Receiver = x.ToUser.UserName, Amount = x.Amount, Type = x.TransferType, Timestamp = x.Timestamp }); return(await query.GetDataTableResultNoLockAsync(model).ConfigureAwait(false)); } }
public async Task <DataTablesResponse> GetIncompleteWithdrawals(DataTablesModel model) { var newest = DateTime.Now.AddHours(-2.0); List <int> pendingApprovalIds = null; using (var approvalContext = DataContextFactory.CreateReadOnlyContext()) { var approvals = await approvalContext.ApprovalQueue .Where(a => a.Type == ApprovalQueueType.WithdrawalReprocessing && a.Status == ApprovalQueueStatus.Pending) .Select(a => a) .ToListNoLockAsync().ConfigureAwait(false); pendingApprovalIds = approvals.Select(a => { int id; bool success = int.TryParse(JsonConvert.DeserializeObject <ReprocessingApprovalDataModel>(a.Data).WithdrawalId, out id); return(new { success, id }); }) .Where(x => x.success) .Select(x => x.id).ToList(); } using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var query = context.Withdraw .AsNoTracking() .Where(w => w.Status == Enums.WithdrawStatus.Processing && w.Confirmed <= newest && !pendingApprovalIds.Contains(w.Id)) .Select(x => new { Id = x.Id, UserName = x.User.UserName, Currency = x.Currency.Symbol, Amount = x.Amount, Address = x.Address, Confirmed = x.Confirmed, RetryCount = x.RetryCount }); var result = await query.GetDataTableResultNoLockAsync(model).ConfigureAwait(false); return(result); } }
public async Task <DataTablesResponse> GetDeposits(DataTablesModel model) { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var query = context.Deposit .AsNoTracking() .Select(x => new { Id = x.Id, UserName = x.User.UserName, Amount = x.Amount, Status = x.Status, Type = x.Type.ToString(), TxId = x.Txid, Conf = x.Confirmations, Timestamp = x.TimeStamp }); return(await query.GetDataTableResultNoLockAsync(model).ConfigureAwait(false)); } }
public async Task <DataTablesResponse> GetWithdrawals(DataTablesModel model) { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var query = context.Withdraw .AsNoTracking() .Select(x => new { Id = x.Id, UserName = x.User.UserName, Amount = x.Amount, Status = x.Status, Confirmed = x.Confirmed, TxId = x.Txid, Address = x.Address, Conf = x.Confirmations, Timestamp = x.TimeStamp, Init = x.IsApi ? "API" : "UI" }); return(await query.GetDataTableResultNoLockAsync(model).ConfigureAwait(false)); } }
public async Task <DataTablesResponse> GetWalletTransactions(WalletTxRequestModel model, DataTablesModel tableModel) { var cacheResult = await CacheService.GetOrSetMemoryAsync(CacheKey.WalletTransactions(model.Currency), TimeSpan.FromMinutes(10), async() => { int currencyId = -1; using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { Entity.Currency selectedCurrency = await context.Currency.FirstOrDefaultNoLockAsync(c => c.Symbol.Equals(model.Currency)); if (selectedCurrency != null) { currencyId = selectedCurrency.Id; } } if (currencyId == -1) { return(null); } List <WalletTransaction> transactions = new List <WalletTransaction>(); using (var service = new AdmintopiaServiceClient()) transactions = await service.GetWalletTransactionsSinceAsync(AdmintopiaService.TransactionDataType.Withdraw, currencyId, WalletTimeoutMinutes, model.BlockLength); return(transactions.Select(x => new { Type = x.Type, Amount = x.Amount, Txid = x.Txid, Address = x.Address })); }); return(cacheResult.GetDataTableResult(tableModel, true)); }
public async Task <ApiUserTradeHistoryResponse> GetUserTradeHistory(ApiUserTradeHistoryRequest request) { var count = Math.Min(request.Count ?? 100, 1000); if (request.TradePairId.HasValue || !string.IsNullOrEmpty(request.Market)) { var tradepair = request.TradePairId.HasValue ? await TradePairReader.GetTradePair(request.TradePairId.Value, true).ConfigureAwait(false) : await TradePairReader.GetTradePair(request.Market.Replace('/', '_'), true).ConfigureAwait(false); if (tradepair == null) { return new ApiUserTradeHistoryResponse { Success = false, Error = "Market not found." } } ; var cacheResult = await CacheService.GetOrSetMemoryAsync(CacheKey.ApiUserTradeHistory(request.UserId.ToString(), tradepair.TradePairId), TimeSpan.FromSeconds(1), async() => { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var history = context.TradeHistory .AsNoTracking() .Where(x => x.TradePairId == tradepair.TradePairId && (x.UserId == request.UserId || x.ToUserId == request.UserId)) .OrderByDescending(x => x.Id) .Take(1000) .Select(x => new ApiTradeHistory { Market = string.Concat(x.TradePair.Currency1.Symbol, "/", x.TradePair.Currency2.Symbol), TradeId = x.Id, Amount = x.Amount, Rate = x.Rate, Type = x.UserId == request.UserId ? TradeHistoryType.Buy.ToString() : TradeHistoryType.Sell.ToString(), TimeStamp = x.Timestamp, TradePairId = x.TradePairId, Fee = x.Fee }); return(await history.ToListNoLockAsync().ConfigureAwait(false)); } }).ConfigureAwait(false); return(new ApiUserTradeHistoryResponse { Success = true, Data = cacheResult.Take(count).ToList() }); } else { var cacheResult = await CacheService.GetOrSetHybridAsync(CacheKey.ApiUserTradeHistory(request.UserId.ToString()), TimeSpan.FromSeconds(20), async() => { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var history = context.TradeHistory .AsNoTracking() .Where(x => x.UserId == request.UserId || x.ToUserId == request.UserId) .OrderByDescending(x => x.Id) .Take(1000) .Select(x => new ApiTradeHistory { Market = string.Concat(x.TradePair.Currency1.Symbol, "/", x.TradePair.Currency2.Symbol), TradeId = x.Id, Amount = x.Amount, Rate = x.Rate, Type = x.UserId == request.UserId ? TradeHistoryType.Buy.ToString() : TradeHistoryType.Sell.ToString(), TimeStamp = x.Timestamp, TradePairId = x.TradePairId, Fee = x.Fee }); return(await history.ToListNoLockAsync().ConfigureAwait(false)); } }).ConfigureAwait(false); return(new ApiUserTradeHistoryResponse { Success = true, Data = cacheResult.Take(count).ToList() }); } }
public async Task <ApiSubmitUserWithdrawResponse> SubmitUserWithdraw(ApiSubmitUserWithdrawRequest request) { var currency = request.CurrencyId.HasValue ? await CurrencyReader.GetCurrency(request.CurrencyId.Value).ConfigureAwait(false) : await CurrencyReader.GetCurrency(request.Currency).ConfigureAwait(false); if (currency == null) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = "Currency not found." } } ; if (currency.Status == CurrencyStatus.Maintenance || currency.Status == CurrencyStatus.Offline || currency.Status == CurrencyStatus.NoConnections) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = $"Currency is currently not available for withdraw, Status: {currency.Status}" } } ; if (request.Amount < currency.WithdrawMin) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = $"Withdraw amount is below the minimum, Minimum: {currency.WithdrawMin:F8} {currency.Symbol}" } } ; if (request.Amount > currency.WithdrawMax) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = $"Withdraw amount is above the maximum, Maximum: {currency.WithdrawMax:F8} {currency.Symbol}" } } ; var balance = await UserBalanceReader.GetBalance(request.UserId.ToString(), currency.CurrencyId).ConfigureAwait(false); if (balance == null || request.Amount > balance.Available) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = "Insufficient funds." } } ; var user = await UserReader.GetUserById(request.UserId.ToString()).ConfigureAwait(false); if (user == null || !user.IsApiWithdrawEnabled) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = "Your API withdraw setting is currently disabled." } } ; var address = request.Address; if (currency.AddressType != AddressType.Standard) { address = $"{request.Address}:{request.PaymentId ?? string.Empty}"; } if (currency.Type == CurrencyType.Fiat) { address = address.TrimEnd(':'); } if (!user.IsApiUnsafeWithdrawEnabled) { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var validAddress = await context.AddressBook .AsNoTracking() .FirstOrDefaultAsync(x => x.UserId == request.UserId && x.CurrencyId == currency.CurrencyId && x.Address == address && x.IsEnabled).ConfigureAwait(false); if (validAddress == null) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = $"Address does not exist in your secure Withdraw Address Book" } } ; } } else { if (currency.CurrencyId == Constant.NZDT_ID && !UserVerificationReader.IsVerified(user.VerificationLevel)) { return(new ApiSubmitUserWithdrawResponse { Success = false, Error = $"Id verification required for NZDT services." }); } if (!await DepositService.ValidateAddress(currency.CurrencyId, address)) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = $"Invalid {currency.Symbol} address." } } ; } var response = await TradeService.CreateWithdraw(request.UserId.ToString(), new CreateWithdrawModel { Address = address, Amount = Math.Max(0, request.Amount), CurrencyId = balance.CurrencyId, TwoFactorToken = string.Empty, Type = WithdrawType.Normal }, true).ConfigureAwait(false); if (response.IsError) { return new ApiSubmitUserWithdrawResponse { Success = false, Error = response.Error } } ; return(new ApiSubmitUserWithdrawResponse { Success = true, Data = response.WithdrawId }); }
public async Task CalculateFeeTotalsAndPortions(DateTime startOfMonthToProcess, Dictionary <int, decimal> tradeHistoryFeeByCurrencyTotals, Dictionary <int, decimal> paytopiaPaymentFeeByCurrencyTotals, Dictionary <int, decimal> tradeHistoryPortionsOfCurrency, Dictionary <int, decimal> paytopiaPaymentPortionsOfCurrency) { Log.Message(LogLevel.Info, "CalculateFeeTotalsAndPortions entered."); List <string> auditMessages = new List <string>(); auditMessages.Add($"CEFS Process. Calculating total fees and portion sizes for CEFS holders."); // get trade histories from the start of last month to the start of this month // (i.e. 1 Oct (incl) - 1 Nov (excl)). var startOfFollowingMonth = startOfMonthToProcess.AddMonths(1).Date; using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var tradeHistoryFeesByCurrency = await(from h in context.TradeHistory join tp in context.TradePair on h.TradePairId equals tp.Id join c in context.Currency on tp.CurrencyId2 equals c.Id where h.Timestamp < startOfFollowingMonth && h.Timestamp >= startOfMonthToProcess group h.Fee by c.Id into g select new { CurrencyId = g.Key, TotalFees = g.Sum() * 2 }).ToListAsync(); // multiplied by two to account for both sides of the trade foreach (var history in tradeHistoryFeesByCurrency) { var tradeHistoryPortionSize = (history.TotalFees * FOUR_POINT_FIVE_PERCENT) / TOTAL_PORTIONS; tradeHistoryPortionsOfCurrency.Add(history.CurrencyId, tradeHistoryPortionSize); tradeHistoryFeeByCurrencyTotals.Add(history.CurrencyId, history.TotalFees); // add auditing to be able to check if there is anything wrong after deployment. auditMessages.Add($"Trade History Total for {history.CurrencyId}: {history.TotalFees}"); auditMessages.Add($"Trade History portion size for {history.CurrencyId}: {tradeHistoryPortionSize}"); } } using (var hubContext = DataContextFactory.CreateContext()) { var paytopiaPaymentsByCurrency = await(from p in hubContext.PaytopiaPayments join pi in hubContext.PaytopiaItems on p.PaytopiaItemId equals pi.Id where p.Timestamp < startOfFollowingMonth && p.Timestamp >= startOfMonthToProcess && p.Status == PaytopiaPaymentStatus.Complete && pi.CurrencyId == 2 group pi.Price by pi.CurrencyId into g select new { CurrencyId = g.Key, TotalPayments = g.Sum() }).ToListAsync(); var paytopiaRefundsByCurrency = await(from p in hubContext.PaytopiaPayments join pi in hubContext.PaytopiaItems on p.PaytopiaItemId equals pi.Id where p.Timestamp < startOfFollowingMonth && p.Timestamp >= startOfMonthToProcess && p.Status == PaytopiaPaymentStatus.Refunded && pi.CurrencyId == 2 group pi.Price by pi.CurrencyId into g select new { CurrencyId = g.Key, TotalRefunds = g.Sum() }).ToListAsync(); foreach (var payment in paytopiaPaymentsByCurrency) { var refund = paytopiaRefundsByCurrency.FirstOrDefault(x => x.CurrencyId == payment.CurrencyId); decimal total = 0; if (refund == null) { total = payment.TotalPayments; } else { total = payment.TotalPayments - refund.TotalRefunds; } var portionSize = (total * FOUR_POINT_FIVE_PERCENT) / TOTAL_PORTIONS; paytopiaPaymentPortionsOfCurrency.Add(payment.CurrencyId, portionSize); paytopiaPaymentFeeByCurrencyTotals.Add(payment.CurrencyId, total); auditMessages.Add($"Paytopia Payments Total for {payment.CurrencyId}: {payment.TotalPayments}"); if (refund != null) { auditMessages.Add($"Paytopia Payment refunds total for {payment.CurrencyId}: {refund.TotalRefunds}"); } auditMessages.Add($"Paytopia Payment portion size for {payment.CurrencyId}: {portionSize}"); } auditMessages.Add($"CEFS Process. Calculation complete."); foreach (var message in auditMessages) { hubContext.LogActivity(Constant.SYSTEM_USER_CEFS.ToString(), message); } await hubContext.SaveChangesAsync(); } Log.Message(LogLevel.Info, "CalculateFeeTotalsAndPortions exited."); }
public async Task <ApiUserOpenOrdersResponse> GetUserOpenOrders(ApiUserOpenOrdersRequest request) { if (request.TradePairId.HasValue || !string.IsNullOrEmpty(request.Market)) { var tradepair = request.TradePairId.HasValue ? await TradePairReader.GetTradePair(request.TradePairId.Value, true).ConfigureAwait(false) : await TradePairReader.GetTradePair(request.Market.Replace('/', '_'), true).ConfigureAwait(false); if (tradepair == null) { return new ApiUserOpenOrdersResponse { Success = false, Error = "Market not found." } } ; using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var openOrders = context.Trade .AsNoTracking() .Where(x => x.UserId == request.UserId && x.TradePairId == tradepair.TradePairId && (x.Status == TradeStatus.Partial || x.Status == TradeStatus.Pending)) .OrderByDescending(x => x.Id) .Select(x => new ApiOpenOrder { Amount = x.Amount, Market = string.Concat(x.TradePair.Currency1.Symbol, "/", x.TradePair.Currency2.Symbol), OrderId = x.Id, Rate = x.Rate, Remaining = x.Remaining, TimeStamp = x.Timestamp, TradePairId = x.TradePairId, Type = x.Type.ToString() }); return(new ApiUserOpenOrdersResponse { Success = true, Data = await openOrders.ToListNoLockAsync().ConfigureAwait(false) }); } } else { using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var openOrders = context.Trade .AsNoTracking() .Where(x => x.UserId == request.UserId && (x.Status == TradeStatus.Partial || x.Status == TradeStatus.Pending)) .OrderByDescending(x => x.Id) .Select(x => new ApiOpenOrder { Amount = x.Amount, Market = string.Concat(x.TradePair.Currency1.Symbol, "/", x.TradePair.Currency2.Symbol), OrderId = x.Id, Rate = x.Rate, Remaining = x.Remaining, TimeStamp = x.Timestamp, TradePairId = x.TradePairId, Type = x.Type.ToString() }); return(new ApiUserOpenOrdersResponse { Success = true, Data = await openOrders.ToListNoLockAsync().ConfigureAwait(false) }); } } }
public async Task <PaytopiaPaymentModel> GetPayment(int id) { PaytopiaPaymentModel item; string currencySymbol; dynamic refCurrency; Entity.Pool refPool; using (var context = DataContextFactory.CreateReadOnlyContext()) { item = await context.PaytopiaPayments .AsNoTracking() .Where(x => x.Id == id) .Select(payment => new PaytopiaPaymentModel { Id = payment.Id, Type = payment.PaytopiaItem.Type, CurrencyId = payment.PaytopiaItem.CurrencyId, Amount = payment.Amount, Status = payment.Status, UserName = payment.User.UserName, IsAnonymous = payment.IsAnonymous, Begins = payment.Begins, Ends = payment.Ends, Timestamp = payment.Timestamp, TransferId = payment.TransferId, RefundId = payment.RefundId, ReferenceCode = payment.ReferenceCode, ReferenceId = payment.ReferenceId, RefundReason = payment.RefundReason, RequestData = payment.RequestData, }).FirstOrDefaultNoLockAsync().ConfigureAwait(false); } using (var exchangeContext = ExchangeDataContextFactory.CreateReadOnlyContext()) { currencySymbol = await exchangeContext.Currency.Where(c => c.Id == item.CurrencyId).Select(c => c.Symbol).FirstOrDefaultNoLockAsync(); refCurrency = await exchangeContext.Currency.Where(c => c.Id == item.ReferenceId).Select(c => new { Name = c.Name, AlgoType = c.Info.AlgoType, Symbol = c.Symbol }).FirstOrDefaultNoLockAsync(); } using (var poolContext = PoolDataContextFactory.CreateContext()) { refPool = await poolContext.Pool.Where(p => p.IsEnabled && p.Id == item.ReferenceId).FirstOrDefaultNoLockAsync(); } item.Symbol = currencySymbol; if (item.ReferenceId > 0) { if (item.Type == PaytopiaItemType.FeaturedCurrency || item.Type == PaytopiaItemType.LottoSlot || item.Type == PaytopiaItemType.RewardSlot || item.Type == PaytopiaItemType.TipSlot) { if (refCurrency != null) { item.ReferenceName = refCurrency.Name; item.ReferenceAlgo = refCurrency.AlgoType; item.ReferenceSymbol = refCurrency.Symbol; } } else if (item.Type == PaytopiaItemType.FeaturedPool || item.Type == PaytopiaItemType.PoolListing) { if (refPool != null) { item.ReferenceName = refPool.Name; item.ReferenceAlgo = refPool.AlgoType; item.ReferenceSymbol = refPool.Symbol; } } } return(item); }
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); }