Exemple #1
0
        public async Task <APIResponse> Profile()
        {
            var rcfg = RuntimeConfigHolder.Clone();
            var user = await GetUserFromDb();

            var userTier = CoreLogic.User.GetTier(user);

            // user challenges
            var challenges = new List <string>();

            if (!user.UserOptions.InitialTfaQuest && !user.TwoFactorEnabled)
            {
                challenges.Add("2fa");
            }

            return(APIResponse.Success(
                       new ProfileView()
            {
                Id = user.UserName,
                Name = CoreLogic.User.HasFilledPersonalData(user.UserVerification) ? (user.UserVerification.FirstName + " " + user.UserVerification.LastName).Trim() : user.UserName,
                Email = user.Email ?? "",
                TfaEnabled = user.TwoFactorEnabled,
                VerifiedL0 = userTier >= UserTier.Tier1,
                VerifiedL1 = userTier >= UserTier.Tier2,
                Challenges = challenges.ToArray(),
            }
                       ));
        }
Exemple #2
0
        public async Task <APIResponse> Estimate([FromBody] EstimateModel model)
        {
            if (BaseValidableModel.IsInvalid(model, out var errFields))
            {
                return(APIResponse.BadRequest(errFields));
            }

            var exchangeCurrency         = FiatCurrency.Usd;
            TradableCurrency?cryptoToken = null;

            // try parse fiat currency
            if (Enum.TryParse(model.Currency, true, out FiatCurrency fc))
            {
                exchangeCurrency = fc;
            }
            // or crypto currency
            else if (Enum.TryParse(model.Currency, true, out TradableCurrency cc))
            {
                cryptoToken = cc;
            }
            else
            {
                return(APIResponse.BadRequest(nameof(model.Currency), "Invalid format"));
            }

            // try parse amount
            if (!BigInteger.TryParse(model.Amount, out var inputAmount) || inputAmount < 1 || (cryptoToken == null && !model.Reversed && inputAmount > long.MaxValue))
            {
                return(APIResponse.BadRequest(nameof(model.Amount), "Invalid amount"));
            }

            // ---

            var userOrNull = await GetUserFromDb();

            var rcfg = RuntimeConfigHolder.Clone();

            // get user limits
            var limits = cryptoToken != null
                                ? DepositLimits(rcfg, cryptoToken.Value)
                                : await DepositLimits(rcfg, DbContext, userOrNull?.Id, exchangeCurrency)
            ;

            // estimate
            var estimation = await Estimation(rcfg, inputAmount, cryptoToken, exchangeCurrency, model.Reversed, 0, limits.Min, limits.Max);

            if (!estimation.TradingAllowed)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }
            if (estimation.IsLimitExceeded)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingExchangeLimit, estimation.View.Limits));
            }

            return(APIResponse.Success(estimation.View));
        }
Exemple #3
0
        private VerificationView MakeVerificationView(DAL.Models.Identity.User user)
        {
            if (user == null)
            {
                throw new ArgumentException("User must be specified");
            }

            var kycFinished = CoreLogic.User.HasKycVerification(user.UserVerification);
            var kycPending  =
                !kycFinished &&
                user.UserVerification?.LastKycTicket != null &&
                user.UserVerification.LastKycTicket.TimeResponded == null &&
                (DateTime.UtcNow - user.UserVerification.LastKycTicket.TimeCreated) < AllowedPeriodBetweenKycRequests
            ;

            var rcfg = RuntimeConfigHolder.Clone();

            var agrSigned = CoreLogic.User.HasTosSigned(user.UserVerification);

            var ret = new VerificationView()
            {
                IsFormFilled = CoreLogic.User.HasFilledPersonalData(user?.UserVerification),

                IsKycPending  = kycPending,
                IsKycFinished = kycFinished,

                IsAgreementSigned = agrSigned,

                FirstName   = user.UserVerification?.FirstName ?? "",
                MiddleName  = user.UserVerification?.MiddleName ?? "",
                LastName    = user.UserVerification?.LastName ?? "",
                Dob         = user.UserVerification?.DoB?.ToString("dd.MM.yyyy") ?? "",
                PhoneNumber = user.UserVerification?.PhoneNumber ?? "",
                Country     = user.UserVerification?.CountryCode ?? "",
                State       = user.UserVerification?.State ?? "",
                City        = user.UserVerification?.City ?? "",
                PostalCode  = user.UserVerification?.PostalCode ?? "",
                Street      = user.UserVerification?.Street ?? "",
                Apartment   = user.UserVerification?.Apartment ?? "",
            };

            return(ret);
        }
Exemple #4
0
        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,
            }
                       ));
        }
Exemple #5
0
        public async Task <APIResponse> Status()
        {
            var user = await GetUserFromDb();

            var rcfg = RuntimeConfigHolder.Clone();

            var ethDepositLimits  = v1.User.BuyGoldController.DepositLimits(rcfg, TradableCurrency.Eth);
            var ethWithdrawLimits = v1.User.SellGoldController.WithdrawalLimits(rcfg, TradableCurrency.Eth);
            var ccDepositLimits   = await v1.User.BuyGoldController.DepositLimits(rcfg, DbContext, user.Id, FiatCurrency.Usd);

            var ccWithdrawLimits = await v1.User.SellGoldController.WithdrawalLimits(rcfg, DbContext, user.Id, FiatCurrency.Usd);

            var ret = new StatusView()
            {
                Trading = new StatusViewTrading()
                {
                    EthAllowed = rcfg.Gold.AllowTradingOverall && rcfg.Gold.AllowTradingEth,
                    CreditCardBuyingAllowed  = rcfg.Gold.AllowTradingOverall && rcfg.Gold.AllowBuyingCreditCard,
                    CreditCardSellingAllowed = rcfg.Gold.AllowTradingOverall && rcfg.Gold.AllowSellingCreditCard,
                },
                Limits = new StatusViewLimits()
                {
                    Eth = new StatusViewLimits.Method()
                    {
                        Deposit = new StatusViewLimits.MinMax()
                        {
                            Min         = ethDepositLimits.Min.ToString(),
                            Max         = ethDepositLimits.Max.ToString(),
                            AccountMax  = "0",
                            AccountUsed = "0",
                        },
                        Withdraw = new StatusViewLimits.MinMax()
                        {
                            Min         = ethWithdrawLimits.Min.ToString(),
                            Max         = ethWithdrawLimits.Max.ToString(),
                            AccountMax  = "0",
                            AccountUsed = "0",
                        }
                    },
                    CreditCardUsd = new StatusViewLimits.Method()
                    {
                        Deposit = new StatusViewLimits.MinMax()
                        {
                            Min         = (long)ccDepositLimits.Min / 100d,
                            Max         = (long)ccDepositLimits.Max / 100d,
                            AccountMax  = (long)ccDepositLimits.AccountMax / 100d,
                            AccountUsed = (long)ccDepositLimits.AccountUsed / 100d,
                        },
                        Withdraw = new StatusViewLimits.MinMax()
                        {
                            Min         = (long)ccWithdrawLimits.Min / 100d,
                            Max         = (long)ccWithdrawLimits.Max / 100d,
                            AccountMax  = (long)ccWithdrawLimits.AccountMax / 100d,
                            AccountUsed = (long)ccWithdrawLimits.AccountUsed / 100d,
                        }
                    },
                },
            };

            return(APIResponse.Success(ret));
        }
        private Task <HexBigInteger> GetWritingGas()
        {
            var rc = _runtimeConfig.Clone();

            return(Task.FromResult(new HexBigInteger(rc.Ethereum.Gas)));
        }
Exemple #7
0
        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();

            // ---

            if (!rcfg.Gold.AllowTradingEth)
            {
                return(APIResponse.BadRequest(APIErrorCode.TradingNotAllowed));
            }

            var limits = DepositLimits(rcfg, TradableCurrency.Eth);

            // estimation
            var estimation = await Estimation(rcfg, inputAmount, TradableCurrency.Eth, exchangeCurrency, model.Reversed, 0d, 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;

            // request
            var request = new DAL.Models.BuyGoldEth()
            {
                Status           = BuySellGoldRequestStatus.Unconfirmed,
                ExchangeCurrency = exchangeCurrency,
                GoldRateCents    = estimation.CentsPerGoldRate,
                EthRateCents     = estimation.CentsPerAssetRate,
                TimeCreated      = timeNow,
                UserId           = user.Id,
            };

            DbContext.BuyGoldEth.Add(request);
            await DbContext.SaveChangesAsync();

            // get a token from eth2gold service
            var contractToken = "";
            {
                try {
                    var reply = await Bus.Request(
                        Eth2Gold.Subject.Request.OrderCreate,
                        new Eth2Gold.Request.OrderCreate()
                    {
                        ExternalID = (ulong)request.Id,
                    },
                        Eth2Gold.Request.OrderCreateReply.Parser
                        );

                    if (reply.ResultCase == Eth2Gold.Request.OrderCreateReply.ResultOneofCase.Token)
                    {
                        if (reply.Token.ToByteArray().Length != 32)
                        {
                            throw new Exception($"token is length of {reply.Token.ToByteArray().Length}");
                        }
                        contractToken = BitConverter.ToString(reply.Token.ToByteArray()).Replace("-", string.Empty);
                    }
                    else
                    {
                        throw new Exception(reply.Error);
                    }
                } catch (Exception e) {
                    Logger.Error(e, "Failed to get token from eth2gold service");
                    return(APIResponse.Failure(APIErrorCode.InternalServerError));
                }
            }

            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,
                EthPerGoldRate = assetPerGold.ToString(),
                Currency = exchangeCurrency.ToString().ToUpper(),
                Expires = ((DateTimeOffset)timeNow.AddHours(1)).ToUnixTimeSeconds(),
                Estimation = estimation.View,
                ContractToken = contractToken,
            }
                       ));
        }