private static async Task <TaskResult> DoTransaction(TransactionRequest request, VooperContext context) { if (!request.Force && request.Amount < 0) { return(new TaskResult(false, "Transaction must be positive.")); } if (request.Amount == 0) { return(new TaskResult(false, "Transaction must have a value.")); } if (request.FromAccount == request.ToAccount) { return(new TaskResult(false, $"An entity cannot send credits to itself.")); } Entity fromUser = await Entity.FindAsync(request.FromAccount); Entity toUser = await Entity.FindAsync(request.ToAccount); if (fromUser == null) { return(new TaskResult(false, $"Failed to find sender {request.FromAccount}.")); } if (toUser == null) { return(new TaskResult(false, $"Failed to find reciever {request.ToAccount}.")); } if (!request.Force && fromUser.Credits < request.Amount) { return(new TaskResult(false, $"{fromUser.Name} cannot afford to send ¢{request.Amount}")); } GovControls govControls = await GovControls.GetCurrentAsync(context); Transaction trans = new Transaction() { ID = Guid.NewGuid().ToString(), Credits = request.Amount, FromUser = request.FromAccount, ToUser = request.ToAccount, Details = request.Detail, Time = DateTime.Now }; await context.Transactions.AddAsync(trans); fromUser.Credits -= request.Amount; toUser.Credits += request.Amount; context.Update(fromUser); context.Update(toUser); await context.SaveChangesAsync(); if (toUser.Id != VooperiaID) { if (request.Tax == ApplicableTax.None && toUser is Group && ((Group)toUser).Group_Category == Group.GroupTypes.Company) { request.Tax = ApplicableTax.Corporate; } if (request.Tax == ApplicableTax.Payroll) { decimal ntax = request.Amount * (govControls.PayrollTaxRate / 100.0m); govControls.UBIAccount += ntax * (govControls.UBIBudgetPercent / 100.0m); govControls.PayrollTaxRevenue += ntax; RequestTransaction(new TransactionRequest(toUser.Id, VooperiaID, ntax, "Payroll Tax", ApplicableTax.None, true)); } else if (request.Tax == ApplicableTax.Sales) { decimal ntax = request.Amount * (govControls.SalesTaxRate / 100.0m); govControls.UBIAccount += ntax * (govControls.UBIBudgetPercent / 100.0m); govControls.SalesTaxRevenue += ntax; RequestTransaction(new TransactionRequest(fromUser.Id, VooperiaID, ntax, "Sales Tax", ApplicableTax.None, true)); } else if (request.Tax == ApplicableTax.Corporate) { decimal ntax = request.Amount * (govControls.CorporateTaxRate / 100.0m); govControls.UBIAccount += ntax * (govControls.UBIBudgetPercent / 100.0m); govControls.CorporateTaxRevenue += ntax; RequestTransaction(new TransactionRequest(toUser.Id, VooperiaID, ntax, "Corporate Tax", ApplicableTax.None, true)); } else if (request.Tax == ApplicableTax.CapitalGains) { decimal ntax = request.Amount * (govControls.CapitalGainsTaxRate / 100.0m); govControls.UBIAccount += ntax * (govControls.UBIBudgetPercent / 100.0m); govControls.CapitalGainsTaxRevenue += ntax; RequestTransaction(new TransactionRequest(fromUser.Id, VooperiaID, ntax, "Capital Gains Tax", ApplicableTax.None, true)); } } else { if (!request.Detail.Contains("Tax") && !request.Detail.Contains("Stock purchase")) { govControls.SalesRevenue += request.Amount; govControls.UBIAccount += (request.Amount * (govControls.UBIBudgetPercent / 100.0m)); } } context.GovControls.Update(govControls); await context.SaveChangesAsync(); return(new TaskResult(true, $"Successfully sent ¢{request.Amount} to {toUser.Name}.")); }
public static async Task RunTrades() { #if DEBUG // Prevent local testing from running the stock exchange return; #endif using (VooperContext context = new VooperContext(VooperContext.DBOptions)) { foreach (StockDefinition def in context.StockDefinitions) { StockOffer sell = await GetLowestSellOffer(def.Ticker, context); StockOffer buy = await GetHighestBuyOffer(def.Ticker, context); // If buy > sell, trade occurs if (buy != null && sell != null && buy.Target >= sell.Target) { GovControls gov = await context.GovControls.AsQueryable().FirstAsync(); int remainder = buy.Amount - sell.Amount; decimal beforePrice = def.Current_Value; decimal tradePrice = buy.Target; int tradeAmount = Math.Min(buy.Amount, sell.Amount); string buyer = buy.Owner_Id; string seller = sell.Owner_Id; string buyId = buy.Id; string sellId = sell.Id; // If remainder is 0, they cancel out perfectly // If remainder > 0, the buy order is not finished and sell is deleted // If remainder < 0, the sell order is not finished and the buy is deleted if (remainder == 0) { context.StockOffers.Remove(sell); context.StockOffers.Remove(buy); } else if (remainder > 0) { context.StockOffers.Remove(sell); buy.Amount = buy.Amount - sell.Amount; context.StockOffers.Update(buy); } else { context.StockOffers.Remove(buy); sell.Amount = sell.Amount - buy.Amount; context.StockOffers.Update(sell); } // Volume stuff if (VolumesMinute.ContainsKey(def.Ticker)) { VolumesMinute[def.Ticker] += tradeAmount; VolumesHour[def.Ticker] += tradeAmount; VolumesDay[def.Ticker] += tradeAmount; } else { VolumesMinute.Add(def.Ticker, tradeAmount); VolumesHour.Add(def.Ticker, tradeAmount); VolumesDay.Add(def.Ticker, tradeAmount); } // End volume stuff decimal totalTrade = tradeAmount * tradePrice; decimal tax = totalTrade * (gov.CapitalGainsTaxRate / 100); await new TransactionRequest(EconomyManager.VooperiaID, sell.Owner_Id, totalTrade - tax, $"Stock sale: {tradeAmount} {def.Ticker}@¢{tradePrice.Round()}", ApplicableTax.None, true).Execute(); gov.CapitalGainsTaxRevenue += tax; gov.UBIAccount += (tax * (gov.UBIBudgetPercent / 100.0m)); context.GovControls.Update(gov); await context.SaveChangesAsync(); await AddStock(def.Ticker, tradeAmount, buyer, context); Console.WriteLine($"Processed Stock sale: {tradeAmount} {def.Ticker}@¢{tradePrice.Round()}"); decimal trueValue = 0.0m; StockOffer nextBuy = await GetHighestBuyOffer(def.Ticker, context); StockOffer nextSell = await GetLowestSellOffer(def.Ticker, context); if (nextBuy == null && nextSell == null) { trueValue = tradePrice; } else if (nextBuy == null) { trueValue = nextSell.Target; } else if (nextSell == null) { trueValue = nextBuy.Target; } else { trueValue = (nextBuy.Target + nextSell.Target) / 2; } StockTradeModel noti = new StockTradeModel() { Ticker = def.Ticker, Amount = tradeAmount, Price = tradePrice, True_Price = trueValue, From = sell.Owner_Id, To = buy.Owner_Id, Buy_Id = buyId, Sell_Id = sellId }; def.Current_Value = noti.True_Price; context.StockDefinitions.Update(def); Entity sellAccount = await Entity.FindAsync(seller); sellAccount.Credits_Invested -= totalTrade; if (sellAccount is User) { context.Users.Update((User)sellAccount); } else if (sellAccount is Group) { context.Groups.Update((Group)sellAccount); } Entity buyAccount = await Entity.FindAsync(buyer); buyAccount.Credits_Invested += totalTrade; if (buyAccount is User) { context.Users.Update((User)buyAccount); } else if (buyAccount is Group) { context.Groups.Update((Group)buyAccount); } await context.SaveChangesAsync(); await ExchangeHub.Current.Clients.All.SendAsync("StockTrade", JsonConvert.SerializeObject(noti)); if (trueValue < beforePrice) { VoopAI.ecoChannel.SendMessageAsync($":chart_with_downwards_trend: ({def.Ticker}) Trade: {tradeAmount}@{buy.Target}, price drop to ¢{trueValue.Round()}"); } else if (trueValue > beforePrice) { VoopAI.ecoChannel.SendMessageAsync($":chart_with_upwards_trend: ({def.Ticker}) Trade: {tradeAmount}@{buy.Target}, price increase to ¢{trueValue.Round()}"); } } // Otherwise move on to the next stock } } }
public async void UpdateRanks() { Console.WriteLine("Doing rank job"); using (VooperContext context = new VooperContext(DBOptions)) { Group government = context.Groups.AsQueryable().FirstOrDefault(x => x.Name == "Vooperia"); if (government == null) { Console.WriteLine("Holy f**k something is wrong."); } leaderboard = context.Users.AsEnumerable().Where(u => u.Email != u.UserName).OrderByDescending(u => u.GetTotalXP()).ToList(); List <SocketGuildUser> userList = new List <SocketGuildUser>(); // Add connected users foreach (User userData in leaderboard) { SocketGuildUser user = null; if (userData.discord_id != null) { //user = server.Users.FirstOrDefault(x => x.Id == (ulong)userData.discord_id); user = server.GetUser((ulong)userData.discord_id); } if (user != null) { // Clear roles if muted if (userData.GetDiscordRoles().Any(r => r.Name == "Muted")) { if (user.Roles.Contains(spleenRole)) { await user.RemoveRoleAsync(spleenRole); } if (user.Roles.Contains(crabRole)) { await user.RemoveRoleAsync(crabRole); } if (user.Roles.Contains(gatyRole)) { await user.RemoveRoleAsync(gatyRole); } if (user.Roles.Contains(corgiRole)) { await user.RemoveRoleAsync(corgiRole); } if (user.Roles.Contains(oofRole)) { await user.RemoveRoleAsync(oofRole); } } else { userList.Add(user); } } } int counter = 0; int totalUsers = userList.Count; GovControls govControls = await GovControls.GetCurrentAsync(context); decimal UBITotal = govControls.UBIAccount; govControls.UBIAccount = 0; context.GovControls.Update(govControls); await context.SaveChangesAsync(); int spleenUserCount = totalUsers / 100; int crabUserCount = (totalUsers / 20) - spleenUserCount; int gatyUserCount = (totalUsers / 10) - spleenUserCount - crabUserCount; int corgiUserCount = (totalUsers / 4) - spleenUserCount - crabUserCount - gatyUserCount; int oofUserCount = (totalUsers / 2) - spleenUserCount - crabUserCount - gatyUserCount - corgiUserCount; int unrankedCount = totalUsers - spleenUserCount - crabUserCount - gatyUserCount - corgiUserCount - oofUserCount; decimal spleenPay = 0.0m; decimal crabPay = 0.0m; decimal gatyPay = 0.0m; decimal corgiPay = 0.0m; decimal oofPay = 0.0m; decimal unrankedPay = 0.0m; if (spleenUserCount > 0) { spleenPay = (UBITotal * (govControls.SpleenPayPercent / 100.0m)) / spleenUserCount; } if (crabUserCount > 0) { crabPay = (UBITotal * (govControls.CrabPayPercent / 100.0m)) / crabUserCount; } if (gatyUserCount > 0) { gatyPay = (UBITotal * (govControls.GatyPayPercent / 100.0m)) / gatyUserCount; } if (corgiUserCount > 0) { corgiPay = (UBITotal * (govControls.CorgiPayPercent / 100.0m)) / corgiUserCount; } if (oofUserCount > 0) { oofPay = (UBITotal * (govControls.OofPayPercent / 100.0m)) / oofUserCount; } if (unrankedCount > 0) { unrankedPay = (UBITotal * (govControls.UnrankedPayPercent / 100.0m)) / unrankedCount; } foreach (SocketGuildUser discordUser in userList) { User webUser = context.Users.FirstOrDefault(u => u.discord_id == discordUser.Id); // Update pfp in storage webUser.Image_Url = webUser.GetPfpUrl(); context.Update(webUser); await context.SaveChangesAsync(); bool hasSpleen = discordUser.Roles.Contains(spleenRole); bool hasCrab = discordUser.Roles.Contains(crabRole); bool hasGaty = discordUser.Roles.Contains(gatyRole); bool hasCorgi = discordUser.Roles.Contains(corgiRole); bool hasOof = discordUser.Roles.Contains(oofRole); bool hasCitizen = discordUser.Roles.Contains(patreonCitizen) || discordUser.Roles.Contains(youtubeCitizen); bool hasSoldier = discordUser.Roles.Contains(patreonSoldier); bool hasLoyalist = discordUser.Roles.Contains(patreonLoyalist); bool hasHero = discordUser.Roles.Contains(patreonHero); bool hasMadlad = discordUser.Roles.Contains(patreonMadlad); bool patron = hasCitizen || hasSoldier || hasLoyalist || hasHero || hasMadlad; // Inactivity tax if (Math.Abs(webUser.Discord_Last_Message_Time.Subtract(DateTime.UtcNow).TotalDays) > 14 && !patron) { decimal tax = webUser.Credits * (govControls.InactivityTaxRate / 100.0M); TransactionRequest req = new TransactionRequest(webUser.Id, EconomyManager.VooperiaID, tax, "Inactivity Tax", ApplicableTax.None, true); TaskResult result = await req.Execute(); if (result.Succeeded) { govControls.InactivityTaxRevenue += tax; // Add to UBI govControls.UBIAccount += tax * (govControls.UBIBudgetPercent / 100.0M); context.GovControls.Update(govControls); await context.SaveChangesAsync(); } // Remove last role if (hasSpleen) { await discordUser.RemoveRoleAsync(spleenRole); } if (hasCrab) { await discordUser.RemoveRoleAsync(crabRole); } if (hasGaty) { await discordUser.RemoveRoleAsync(gatyRole); } if (hasCorgi) { await discordUser.RemoveRoleAsync(corgiRole); } if (hasOof) { await discordUser.RemoveRoleAsync(oofRole); } continue; } // Set district if (!String.IsNullOrWhiteSpace(webUser.district)) { var oldDistrictRoles = discordUser.Roles.Where(x => x.Name.Contains("District") && !x.Name.Contains(webUser.district)); if (oldDistrictRoles.Count() > 0) { await discordUser.RemoveRolesAsync(oldDistrictRoles); } if (!discordUser.Roles.Any(x => x.Name == webUser.district + " District")) { await discordUser.AddRoleAsync(districtRoles[webUser.district + " District"]); } } // Spleen rank if (counter <= spleenUserCount) { // Add new role if (!hasSpleen) { await discordUser.AddRoleAsync(spleenRole); } // Remove last role if (hasCrab) { await discordUser.RemoveRoleAsync(crabRole); } if (hasGaty) { await discordUser.RemoveRoleAsync(gatyRole); } if (hasCorgi) { await discordUser.RemoveRoleAsync(corgiRole); } if (hasOof) { await discordUser.RemoveRoleAsync(oofRole); } if (webUser != null) { //TransactionRequest transaction = new TransactionRequest(webUser.economy_id, government.economy_id, 238827, "UBI Mistake Fix", ApplicableTax.None, true); TransactionRequest transaction = new TransactionRequest(government.Id, webUser.Id, spleenPay, "UBI Payment", ApplicableTax.None, true); EconomyManager.RequestTransaction(transaction); } } // Crab rank else if (counter <= spleenUserCount + crabUserCount) { // Add new role if (!hasCrab) { await discordUser.AddRoleAsync(crabRole); } // Remove last role if (hasSpleen) { await discordUser.RemoveRoleAsync(spleenRole); } if (hasGaty) { await discordUser.RemoveRoleAsync(gatyRole); } if (hasCorgi) { await discordUser.RemoveRoleAsync(corgiRole); } if (hasOof) { await discordUser.RemoveRoleAsync(oofRole); } if (webUser != null) { //TransactionRequest transaction = new TransactionRequest(webUser.economy_id, government.economy_id, 146267, "UBI Mistake Fix", ApplicableTax.None, true); TransactionRequest transaction = new TransactionRequest(government.Id, webUser.Id, crabPay, "UBI Payment", ApplicableTax.None, true); EconomyManager.RequestTransaction(transaction); } } // Gaty rank else if (counter <= spleenUserCount + crabUserCount + gatyUserCount) { // Add new role if (!hasGaty) { await discordUser.AddRoleAsync(gatyRole); } // Remove last role if (hasSpleen) { await discordUser.RemoveRoleAsync(spleenRole); } if (hasCrab) { await discordUser.RemoveRoleAsync(crabRole); } if (hasCorgi) { await discordUser.RemoveRoleAsync(corgiRole); } if (hasOof) { await discordUser.RemoveRoleAsync(oofRole); } if (webUser != null) { //TransactionRequest transaction = new TransactionRequest(webUser.economy_id, government.economy_id, 125698, "UBI Mistake Fix", ApplicableTax.None, true); TransactionRequest transaction = new TransactionRequest(government.Id, webUser.Id, gatyPay, "UBI Payment", ApplicableTax.None, true); EconomyManager.RequestTransaction(transaction); } } // Corgi rank else if (counter <= spleenUserCount + crabUserCount + gatyUserCount + corgiUserCount) { // Add new role if (!hasCorgi) { await discordUser.AddRoleAsync(corgiRole); } // Remove last role if (hasSpleen) { await discordUser.RemoveRoleAsync(spleenRole); } if (hasCrab) { await discordUser.RemoveRoleAsync(crabRole); } if (hasGaty) { await discordUser.RemoveRoleAsync(gatyRole); } if (hasOof) { await discordUser.RemoveRoleAsync(oofRole); } if (webUser != null) { //TransactionRequest transaction = new TransactionRequest(webUser.economy_id, government.economy_id, 110369, "UBI Mistake Fix", ApplicableTax.None, true); TransactionRequest transaction = new TransactionRequest(government.Id, webUser.Id, corgiPay, "UBI Payment", ApplicableTax.None, true); EconomyManager.RequestTransaction(transaction); } } // Oof rank else if (counter <= spleenUserCount + crabUserCount + gatyUserCount + corgiUserCount + oofUserCount) { // Add new role if (!hasOof) { await discordUser.AddRoleAsync(oofRole); } // Remove last role if (hasSpleen) { await discordUser.RemoveRoleAsync(spleenRole); } if (hasCrab) { await discordUser.RemoveRoleAsync(crabRole); } if (hasGaty) { await discordUser.RemoveRoleAsync(gatyRole); } if (hasCorgi) { await discordUser.RemoveRoleAsync(corgiRole); } if (webUser != null) { //TransactionRequest transaction = new TransactionRequest(webUser.economy_id, government.economy_id, 91085, "UBI Mistake Fix", ApplicableTax.None, true); TransactionRequest transaction = new TransactionRequest(government.Id, webUser.Id, oofPay, "UBI Payment", ApplicableTax.None, true); EconomyManager.RequestTransaction(transaction); } } // Unranked else { // Remove last role if (hasSpleen) { await discordUser.RemoveRoleAsync(spleenRole); } if (hasCrab) { await discordUser.RemoveRoleAsync(crabRole); } if (hasGaty) { await discordUser.RemoveRoleAsync(gatyRole); } if (hasCorgi) { await discordUser.RemoveRoleAsync(corgiRole); } if (hasOof) { await discordUser.RemoveRoleAsync(oofRole); } if (webUser != null) { //TransactionRequest transaction = new TransactionRequest(webUser.economy_id, government.economy_id, 125698, "UBI Mistake Fix", ApplicableTax.None, true); TransactionRequest transaction = new TransactionRequest(government.Id, webUser.Id, unrankedPay, "UBI Payment", ApplicableTax.None, true); EconomyManager.RequestTransaction(transaction); } } if (patron) { webUser = await context.Users.FindAsync(webUser.Id); if (hasMadlad) { webUser.Credits += 500; } else if (hasHero) { webUser.Credits += 350; } else if (hasLoyalist) { webUser.Credits += 175; } else if (hasSoldier) { webUser.Credits += 60; } else if (hasCitizen) { webUser.Credits += 20; } context.Update(webUser); await context.SaveChangesAsync(); } counter++; } } Console.WriteLine("Finished rank system"); }