From 6928770da7c91696eaf2c06547cb56085fd6a1e9 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Fri, 3 Oct 2025 16:14:24 +0700 Subject: [PATCH] Block user to create strategy with over allocation --- .../Abstractions/IBotService.cs | 10 +++ .../ManageBot/BotService.cs | 62 +++++++++++++++++++ .../ManageBot/StartBotCommandHandler.cs | 8 +++ 3 files changed, 80 insertions(+) diff --git a/src/Managing.Application/Abstractions/IBotService.cs b/src/Managing.Application/Abstractions/IBotService.cs index 20c145ac..f246d54d 100644 --- a/src/Managing.Application/Abstractions/IBotService.cs +++ b/src/Managing.Application/Abstractions/IBotService.cs @@ -26,6 +26,16 @@ public interface IBotService Task UpdateBotStatisticsAsync(Guid identifier); Task SaveBotStatisticsAsync(Bot bot); + /// + /// Computes the remaining available USDC allocation for the provided account, + /// subtracting the sum of BotTradingBalance from other bots using the same account. + /// Optionally exclude a specific bot identifier from the allocation sum (useful for restarts/updates). + /// + /// Target account. + /// Bot identifier to exclude from allocation sum. + /// Available USDC amount that can be allocated. + Task GetAvailableAllocationUsdAsync(Account account, Guid excludeIdentifier = default); + /// /// Gets paginated bots with filtering and sorting /// diff --git a/src/Managing.Application/ManageBot/BotService.cs b/src/Managing.Application/ManageBot/BotService.cs index cd687d03..1e2ba4e7 100644 --- a/src/Managing.Application/ManageBot/BotService.cs +++ b/src/Managing.Application/ManageBot/BotService.cs @@ -115,6 +115,14 @@ namespace Managing.Application.ManageBot if (account.Exchange == TradingExchanges.Evm || account.Exchange == TradingExchanges.GmxV2) { + // Allocation guard: ensure this bot's configured balance fits in remaining allocation + var availableAllocation = await GetAvailableAllocationUsdAsync(account, identifier); + if (botConfig.BotTradingBalance > availableAllocation) + { + throw new InvalidOperationException( + $"Insufficient available allocation on account '{account.Name}'. Requested: {botConfig.BotTradingBalance:F2} USDC, Available: {availableAllocation:F2} USDC."); + } + var balanceCheckResult = await CheckAccountBalancesAsync(account); if (!balanceCheckResult.IsSuccessful) { @@ -370,6 +378,60 @@ namespace Managing.Application.ManageBot } } + public async Task GetAvailableAllocationUsdAsync(Account account, Guid excludeIdentifier = default) + { + try + { + return await ServiceScopeHelpers.WithScopedService( + _scopeFactory, + async repo => + { + // Get all bots for the account's user + var botsForUser = await repo.GetBotsByUserIdAsync(account.User.Id); + + // Sum allocations for bots using this account name, excluding the requested identifier + decimal totalAllocatedForAccount = 0m; + foreach (var bot in botsForUser) + { + if (excludeIdentifier != default && bot.Identifier == excludeIdentifier) + { + continue; + } + + var grain = _grainFactory.GetGrain(bot.Identifier); + TradingBotConfig config; + try + { + config = await grain.GetConfiguration(); + } + catch + { + continue; + } + + if (string.Equals(config.AccountName, account.Name, StringComparison.OrdinalIgnoreCase)) + { + totalAllocatedForAccount += config.BotTradingBalance; + } + } + + // Current USDC balance for the account + var balances = await ServiceScopeHelpers.WithScopedService>( + _scopeFactory, async exchangeService => await exchangeService.GetBalances(account)); + var usdc = balances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC"); + var usdcValue = usdc?.Value ?? 0m; + + var available = usdcValue - totalAllocatedForAccount; + return available < 0m ? 0m : available; + }); + } + catch + { + // On failure, be safe and return 0 to block over-allocation + return 0m; + } + } + public async Task<(IEnumerable Bots, int TotalCount)> GetBotsPaginatedAsync( int pageNumber, int pageSize, diff --git a/src/Managing.Application/ManageBot/StartBotCommandHandler.cs b/src/Managing.Application/ManageBot/StartBotCommandHandler.cs index f4ee4cac..45fcc4e2 100644 --- a/src/Managing.Application/ManageBot/StartBotCommandHandler.cs +++ b/src/Managing.Application/ManageBot/StartBotCommandHandler.cs @@ -72,6 +72,14 @@ namespace Managing.Application.ManageBot } } + // Enforce allocation limit across all bots using the same account + var availableAllocation = await _botService.GetAvailableAllocationUsdAsync(account, default); + if (request.Config.BotTradingBalance > availableAllocation) + { + throw new InvalidOperationException( + $"Insufficient available allocation on account '{account.Name}'. Requested: {request.Config.BotTradingBalance:F2} USDC, Available: {availableAllocation:F2} USDC."); + } + try { var botGrain = _grainFactory.GetGrain(Guid.NewGuid());