private void HandleMessage(object _, MsgHandlerEventArgs args) { try { _dbContext.DetachEverything(); var evt = Eth2Gold.Event.OrderDeposited.Parser.ParseFrom(args.Message.Data); // find request var id = (long)evt.ExternalID; var row = (from r in _dbContext.BuyGoldEth where r.Id == id select r) .AsTracking() .LastOrDefault() ; BigInteger ethAmount = BigInteger.Zero; try { if (row == null) { throw new Exception("Order not found by given external id"); } if (!BigInteger.TryParse(evt.EthAmount, out ethAmount) || ethAmount <= 0) { throw new Exception("Failed to parse ETH amount"); } } catch (Exception e) { Logger.Error(e, $"Failed to process order #{id}"); return; } if (row.Status == BuySellGoldRequestStatus.Confirmed) { long?dealGoldPrice = row.GoldRateCents; long?dealEthPrice = row.EthRateCents; // use fresh prices (see BuyGoldCrypto()) if ((DateTime.UtcNow - row.TimeCreated) >= TimeSpan.FromHours(1)) { dealGoldPrice = null; dealEthPrice = null; } var estimation = CoreLogic.Finance.Estimation.BuyGoldCrypto( services: _services, ethereumToken: TradableCurrency.Eth, fiatCurrency: row.ExchangeCurrency, cryptoAmount: ethAmount, knownGoldRateCents: dealGoldPrice, knownCryptoRateCents: dealEthPrice ).Result; // price provider failed if (!estimation.Allowed) { Logger.Error($"Failed to process order #{id}, estimation failed"); return; } try { // history var finHistory = new DAL.Models.UserFinHistory() { Status = UserFinHistoryStatus.Completed, Type = UserFinHistoryType.GoldDeposit, Source = "ETH", SourceAmount = TextFormatter.FormatTokenAmountFixed(ethAmount, TokensPrecision.Ethereum), Destination = "GOLD", DestinationAmount = TextFormatter.FormatTokenAmountFixed(estimation.ResultGoldAmount, TokensPrecision.Sumus), Comment = "", TimeCreated = DateTime.UtcNow, UserId = row.UserId, }; _dbContext.UserFinHistory.Add(finHistory); _dbContext.SaveChanges(); row.Status = BuySellGoldRequestStatus.Success; row.TimeCompleted = DateTime.UtcNow; row.RelFinHistoryId = finHistory.Id; _dbContext.SaveChanges(); var ok = CoreLogic.Finance.SumusWallet.Refill(_services, row.UserId, estimation.ResultGoldAmount.FromSumus(), SumusToken.Gold).Result; if (!ok) { Logger.Error($"Deposit request #{row.Id} completed but wallet not refilled with {estimation.ResultGoldAmount.FromSumus()} GOLD"); } else { Logger.Information($"Deposit request #{row.Id} completed"); } } catch (Exception e) { Logger.Error(e, $"Failed to process order #{id}, while saving to DB"); return; } } // reply args.Message.ArrivalSubcription.Connection.Publish( args.Message.Reply, new Eth2Gold.Event.OrderDepositedAck().ToByteArray() ); } catch (Exception e) { Logger.Error(e, $"Failed to process message"); } }
public async Task <APIResponse> AssetEth([FromBody] AssetEthModel model) { // validate if (BaseValidableModel.IsInvalid(model, out var errFields)) { return(APIResponse.BadRequest(errFields)); } // try parse amount if (!BigInteger.TryParse(model.Amount, out var inputAmount) || inputAmount < 1) { return(APIResponse.BadRequest(nameof(model.Amount), "Invalid amount")); } // try parse fiat currency var exchangeCurrency = FiatCurrency.Usd; if (Enum.TryParse(model.Currency, true, out FiatCurrency fc)) { exchangeCurrency = fc; } // --- var rcfg = RuntimeConfigHolder.Clone(); var user = await GetUserFromDb(); var userTier = CoreLogic.User.GetTier(user); var agent = GetUserAgentInfo(); if (userTier < UserTier.Tier2) { return(APIResponse.BadRequest(APIErrorCode.AccountNotVerified)); } // --- if (!rcfg.Gold.AllowTradingEth) { return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed)); } var limits = WithdrawalLimits(rcfg, TradableCurrency.Eth); var estimation = await Estimation(rcfg, inputAmount, TradableCurrency.Eth, exchangeCurrency, model.EthAddress, model.Reversed, limits.Min, limits.Max); if (!estimation.TradingAllowed || estimation.ResultCurrencyAmount < 1) { return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed)); } if (estimation.IsLimitExceeded) { return(APIResponse.BadRequest(APIErrorCode.TradingExchangeLimit, estimation.View.Limits)); } // limit gold amount to max available if (estimation.ResultGoldAmount.FromSumus() > user.UserSumusWallet.BalanceGold) { estimation = await Estimation(rcfg, user.UserSumusWallet.BalanceGold.ToSumus(), TradableCurrency.Eth, exchangeCurrency, model.EthAddress, false, limits.Min, limits.Max); if (!estimation.TradingAllowed || estimation.ResultCurrencyAmount < 1) { return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed)); } if (estimation.IsLimitExceeded) { return(APIResponse.BadRequest(APIErrorCode.TradingExchangeLimit, estimation.View.Limits)); } } var timeNow = DateTime.UtcNow; // history var finHistory = new DAL.Models.UserFinHistory() { Status = UserFinHistoryStatus.Unconfirmed, Type = UserFinHistoryType.GoldSell, Source = "GOLD", SourceAmount = TextFormatter.FormatTokenAmountFixed(estimation.ResultGoldAmount, TokensPrecision.Sumus), Destination = "ETH", DestinationAmount = TextFormatter.FormatTokenAmountFixed(estimation.ResultCurrencyAmount, TokensPrecision.Ethereum), Comment = "", TimeCreated = timeNow, UserId = user.Id, }; DbContext.UserFinHistory.Add(finHistory); await DbContext.SaveChangesAsync(); // request var request = new DAL.Models.SellGoldEth() { Status = BuySellGoldRequestStatus.Unconfirmed, GoldAmount = estimation.ResultGoldAmount.FromSumus(), Destination = model.EthAddress, EthAmount = estimation.ResultCurrencyAmount.FromSumus(), ExchangeCurrency = exchangeCurrency, GoldRateCents = estimation.CentsPerGoldRate, EthRateCents = estimation.CentsPerAssetRate, TimeCreated = timeNow, RelFinHistoryId = finHistory.Id, UserId = user.Id, }; // add and save DbContext.SellGoldEth.Add(request); await DbContext.SaveChangesAsync(); var assetPerGold = CoreLogic.Finance.Estimation.AssetPerGold(TradableCurrency.Eth, estimation.CentsPerAssetRate, estimation.CentsPerGoldRate); return(APIResponse.Success( new AssetEthView() { RequestId = request.Id, EthRate = estimation.CentsPerAssetRate / 100d, GoldRate = estimation.CentsPerGoldRate / 100d, Currency = exchangeCurrency.ToString().ToUpper(), EthPerGoldRate = assetPerGold.ToString(), Estimation = estimation.View, } )); }
private void HandleMessage(object _, MsgHandlerEventArgs args) { try { _dbContext.DetachEverything(); var request = MintSender.Watcher.Event.Refill.Parser.ParseFrom(args.Message.Data); if (request.Service != "core_gold_deposit") { return; } // find wallet var row = (from r in _dbContext.UserSumusWallet where r.PublicKey == request.PublicKey select r) .AsNoTracking() .LastOrDefault() ; if (row == null) { throw new Exception($"Wallet #{request.PublicKey} not found"); } // parse amount var ok = decimal.TryParse(request.Amount, System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture, out var amount); if (!ok) { throw new Exception($"Failed to parse amount"); } // truncate amount = amount.ToSumus().FromSumus(); // parse token ok = Common.Sumus.Token.ParseToken(request.Token, out var token); if (!ok) { throw new Exception($"Failed to parse token"); } // history var finHistory = new DAL.Models.UserFinHistory() { Status = UserFinHistoryStatus.Completed, Type = UserFinHistoryType.GoldDeposit, Source = "", SourceAmount = "", Destination = "GOLD", DestinationAmount = TextFormatter.FormatTokenAmountFixed(amount), Comment = "", TimeCreated = DateTime.UtcNow, UserId = row.UserId, }; _dbContext.UserFinHistory.Add(finHistory); _dbContext.SaveChanges(); // refill if (!CoreLogic.Finance.SumusWallet.Refill(_services, row.UserId, amount, token).Result) { throw new Exception($"Failed to process refilling"); } // reply args.Message.ArrivalSubcription.Connection.Publish( args.Message.Reply, new MintSender.Watcher.Event.RefillAck() { Success = true }.ToByteArray() ); } catch (Exception e) { Logger.Error(e, $"Failed to process message"); // reply args.Message.ArrivalSubcription.Connection.Publish( args.Message.Reply, new MintSender.Watcher.Event.RefillAck() { Success = false, Error = e.ToString() }.ToByteArray() ); } }