public async Task ShouldSetEnumStatus()
        {
            var tableName = "integration";
            await _sut.DeleteTableAsync(tableName);

            await _sut.CreateTableAsync(tableName);

            var userId = 123;

            var rowKey = (DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks).ToString();

            var userWithDrawalEntity = await _sut.Retrieve <UserWithdrawal>(tableName, userId.ToString(), rowKey);

            Assert.IsNull(userWithDrawalEntity);

            userWithDrawalEntity = new UserWithdrawal(userId)
            {
                RowKey = rowKey, State = WithdrawalState.Failed, StartDate = DateTime.UtcNow, Timestamp = DateTimeOffset.UtcNow
            };
            await _sut.InsertOrMergeEntity(tableName, userWithDrawalEntity);

            var userWithdrawal = await _sut.Retrieve <UserWithdrawal>(tableName, userId.ToString(), rowKey);

            Assert.IsNotNull(userWithdrawal);
            Assert.AreEqual(userWithdrawal.State, userWithDrawalEntity.State);
        }
        public long Create(UserWithdrawal UserWithdrawal)
        {
            const string sql = @"INSERT INTO [dbo].[UserWithdrawals] ([UserAccountId], [UserWalletId], [Address],[Tag], [Amount], [Status], [Timestamp], [Remark], [OrderNo], [TransactionId], [SelfPlatform],[RequestId],[CryptoId],[CryptoCode])
                                      VALUES (@UserAccountId, @UserWalletId, @Address,@Tag, @Amount, @Status, @Timestamp, @Remark, @OrderNo, @TransactionId, @SelfPlatform,@RequestId,@CryptoId,@CryptoCode); SELECT SCOPE_IDENTITY()";

            using (var conn = WriteConnection())
            {
                return(conn.ExecuteScalar <long>(sql, UserWithdrawal));
            }
        }
Beispiel #3
0
        public async Task <UserWithdrawal> GetLastWithdrawal()
        {
            UserWithdrawal result   = null;
            var            request  = GetRequest("api/Withdrawal/GetLastWithdrawal");
            var            response = await Client.SendAsync(request);

            if (response.StatusCode == HttpStatusCode.OK)
            {
                var responseText = await response.Content.ReadAsStringAsync();

                result = JSSerializer.Deserialize <UserWithdrawal>(responseText);
            }
            return(result);
        }
        private async Task SetWithdrawalState(bool isSuccess, UserWithdrawal userWithdrawal, long chatId, int chatUserId, double amount, string transactionId)
        {
            if (!isSuccess)
            {
                userWithdrawal.State = WithdrawalState.Failed;
                await _withdrawalRepository.AddOrUpdate(userWithdrawal);

                await _botService.SendTextMessage(chatId, ReplyConstants.UnableToWithdraw);
            }
            else
            {
                await SetWithdrawalSuccess(userWithdrawal, chatId, chatUserId, amount, transactionId);
            }
        }
        private async Task SetWithdrawalSuccess(UserWithdrawal userWithdrawal, long chatId, int chatUserId, double amount, string transactionId)
        {
            var userBalance = await _userBalanceRepository.Get(chatUserId);

            userBalance.Balance -= amount;
            await _userBalanceRepository.Update(userBalance);

            if (userBalance.Balance < 0)
            {
                _logger.LogError($"Balance for {chatUserId} is below 0 after withdrawal transaction {transactionId}");
            }
            userWithdrawal.State = WithdrawalState.Completed;
            await _withdrawalRepository.AddOrUpdate(userWithdrawal);

            await _botService.SendTextMessage(chatId, ReplyConstants.WithdrawalSuccess);
        }
        //private WithdrawOM WithdrawalToMerchantAccount(UserWallet fromWallet, UserWithdrawal fromWithdraw, UserWithdrawalFee fromWithdrawFee, MerchantWallet toWallet, Cryptocurrency cryptocurrency)
        //{
        //    var mastSettings = new MasterSettingDAC().SelectByGroup("UserWithdrawal");
        //    using (var scope = new TransactionScope())
        //    {
        //        //提币
        //        fromWithdraw.Status = Framework.Enums.TransactionStatus.Confirmed;
        //        fromWithdraw.TransactionId = toWallet.MerchantAccountId.ToString("N");
        //        fromWithdraw.SelfPlatform = true;//平台内提币
        //        fromWithdraw.Id = new UserWithdrawalDAC().Create(fromWithdraw);
        //        fromWithdrawFee.WithdrawalId = fromWithdraw.Id;
        //        fromWithdrawFee.Fee = fromWithdraw.Amount * Convert.ToDecimal(mastSettings.First(e => e.Name == "UserWithdrawal_ToMerchant").Value);
        //        fromWithdrawFee.Fee = fromWithdrawFee.Fee.ToSpecificDecimal(cryptocurrency.DecimalPlace);
        //        new UserWithdrawalFeeDAC().Create(fromWithdrawFee);

        //        new UserWalletDAC().Decrease(fromWallet.Id, fromWithdraw.Amount);

        //        new UserWalletStatementDAC().Insert(new UserWalletStatement
        //        {
        //            WalletId = fromWallet.Id,
        //            Action = MerchantWalletStatementAction.Withdrawal,
        //            Amount = -fromWithdraw.Amount,
        //            Balance = fromWallet.Balance - fromWithdraw.Amount,
        //            Timestamp = DateTime.UtcNow
        //        });

        //        //充币
        //        var amount = fromWithdraw.Amount - fromWithdrawFee.Fee;
        //        if (amount <= 0)
        //        {
        //            throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.到账数量不能为零或者负数);
        //        }

        //        var deposit = new MerchantDepositDAC().Insert(new MerchantDeposit
        //        {
        //            MerchantAccountId = toWallet.MerchantAccountId,
        //            MerchantWalletId = toWallet.Id,
        //            FromAddress = fromWallet.Address,
        //            ToAddress = toWallet.Address,
        //            Amount = fromWithdraw.Amount - fromWithdrawFee.Fee,
        //            Status = Framework.Enums.TransactionStatus.Confirmed,
        //            Timestamp = DateTime.UtcNow,
        //            OrderNo = CreateOrderno(),
        //            TransactionId = fromWallet.UserAccountId.ToString("N"),
        //            SelfPlatform = true
        //        });
        //        new MerchantWalletDAC().Increase(toWallet.Id, amount);
        //        new MerchantWalletStatementDAC().Insert(new MerchantWalletStatement
        //        {
        //            WalletId = toWallet.Id,
        //            Action = MerchantWalletStatementAction.Deposit,
        //            Amount = amount,
        //            Balance = toWallet.Balance + amount,
        //            Timestamp = DateTime.UtcNow
        //        });

        //        new FiiiPayPushComponent().PushWithdrawCompleted(fromWithdraw.Id);
        //        scope.Complete();

        //        UserMSMQ.PubMerchantDeposit(deposit.Id, 0);
        //    }

        //    return new WithdrawOM
        //    {
        //        OrderId = fromWithdraw.Id,
        //        OrderNo = fromWithdraw.OrderNo,
        //        Timestamp = fromWithdraw.Timestamp.ToUnixTime().ToString()
        //    };
        //}

        private WithdrawOM CancelWithdrawal(UserWithdrawal fromWithdraw)
        {
            fromWithdraw.Status        = TransactionStatus.Cancelled;
            fromWithdraw.TransactionId = Guid.NewGuid().ToString("N");
            fromWithdraw.SelfPlatform  = true;//平台内提币

            using (var scope = new TransactionScope())
            {
                fromWithdraw.Id = new UserWithdrawalDAC().Create(fromWithdraw);

                new UserTransactionDAC().Insert(new UserTransaction
                {
                    Id         = Guid.NewGuid(),
                    AccountId  = fromWithdraw.UserAccountId,
                    CryptoId   = fromWithdraw.CryptoId,
                    CryptoCode = fromWithdraw.CryptoCode,
                    Type       = UserTransactionType.Withdrawal,
                    DetailId   = fromWithdraw.Id.ToString(),
                    Status     = (byte)fromWithdraw.Status,
                    Timestamp  = fromWithdraw.Timestamp,
                    Amount     = fromWithdraw.Amount,
                    OrderNo    = fromWithdraw.OrderNo
                });

                var fromWithdrawFee = new UserWithdrawalFee
                {
                    Amount       = fromWithdraw.Amount,
                    Fee          = 0,
                    Timestamp    = DateTime.UtcNow,
                    WithdrawalId = fromWithdraw.Id
                };

                new UserWithdrawalFeeDAC().Create(fromWithdrawFee);

                scope.Complete();
            }

            UserMSMQ.PubUserWithdrawReject(fromWithdraw.Id, 0);

            return(new WithdrawOM
            {
                OrderId = fromWithdraw.Id,
                OrderNo = fromWithdraw.OrderNo,
                Timestamp = fromWithdraw.Timestamp.ToUnixTime().ToString()
            });
        }
        public void InitTransactionId(UserWithdrawal withdrawal)
        {
            const string sql = @"UPDATE [dbo].[UserWithdrawals]
                                    SET [TransactionId] = @TransactionId
                                  WHERE UserAccountId=@UserAccountId AND UserWalletId=@UserWalletId AND RequestId=@RequestId";

            using (var conn = ReadConnection())
            {
                conn.Execute(sql, new
                {
                    UserAccountId = withdrawal.UserAccountId,
                    UserWalletId  = withdrawal.UserWalletId,
                    RequestId     = withdrawal.RequestId.Value,
                    withdrawal.TransactionId
                });
            }
        }
        private async Task <bool> VerifyTx(string transactionId, UserWithdrawal userWithdrawal)
        {
            try
            {
                var txResponse = await _mhcHttpClient.GetTx(transactionId);

                if (txResponse.TxResult?.Transaction?.Status == "ok")
                {
                    userWithdrawal.State = WithdrawalState.Completed;
                    await _withdrawalRepository.AddOrUpdate(userWithdrawal);

                    return(true);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"Could not verify transaction {transactionId}", ex);
            }

            return(false);
        }
Beispiel #9
0
        public async Task <ActionResult <string> > MakeWithdrawal(int reqId, string status, string counts, [FromBody] Withdrawal withdrawal)
        {
            if (ModelState.IsValid && withdrawal != null && reqId > 0)
            {
                Request request = _context.Request.Where(r => r.Id == reqId).FirstOrDefault <Request>();
                if (request == null)
                {
                    return(NotFound("User not found"));
                }
                User user = _context.User.Where(u => u.Id == _context.Request.Where(r => r.Id == request.Id).FirstOrDefault <Request>().User.Id).FirstOrDefault <User>();
                if (user == null)
                {
                    return(NotFound("User not found"));
                }

                withdrawal.DateTime = DateTime.Now; // get current date and time;

                UserWithdrawal userWithdrawal = new UserWithdrawal()
                {
                    Withdrawal = withdrawal,
                    User       = user
                };
                if (status.Contains("E0"))
                {
                    request.Response = "Withdrawal successful";
                }
                else
                {
                    request.Response = "Withdrawal status: " + status;
                }

                string strV = "" + counts[0] + "" + counts[1];
                int    c100 = int.Parse(strV);
                strV = "" + counts[2] + "" + counts[3];
                int c50 = int.Parse(strV);
                if (c100 + c50 <= 0)
                {
                    request.isCompleted = true;
                    request.Counts      = counts;
                    _context.Request.Update(request);
                    await _context.SaveChangesAsync();

                    return(request.Response);
                }
                Safe safe = _context.Safe.FirstOrDefault <Safe>();
                safe.Bill100        = safe.Bill100 - c100;
                safe.Bill50         = safe.Bill50 - c50;
                withdrawal.Value    = c100 * 100 + c50 * 50;
                request.isCompleted = true;
                request.Counts      = counts;
                _context.Request.Update(request);
                _context.Withdrawal.Add(withdrawal);
                _context.UserWithdrawal.Add(userWithdrawal);
                _context.Safe.Update(safe);
                await _context.SaveChangesAsync();

                int deposits    = (int)new CreditsController(_context).GetUserTotalCredit(user.Id).Result.Value;
                int withdrawals = (int)GetUserTotalWithdrawal(user.Id).Result.Value;
                int balance     = deposits - withdrawals;
                return(request.Response);
            }
            else
            {
                return(BadRequest("inavlid withdrawal request details"));
            }
        }
        private WithdrawOM WithdrawalToUserAccount(UserWallet fromWallet, UserWithdrawal fromWithdraw, UserWallet toWallet)
        {
            var         mastSettings = new MasterSettingDAC().SelectByGroup("UserWithdrawal");
            UserDeposit model        = new UserDeposit();

            using (var scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 1, 30)))
            {
                fromWithdraw.Status        = TransactionStatus.Confirmed;
                fromWithdraw.TransactionId = toWallet.UserAccountId.ToString("N");
                fromWithdraw.SelfPlatform  = true;//平台内提币
                fromWithdraw.Id            = new UserWithdrawalDAC().Create(fromWithdraw);

                new UserTransactionDAC().Insert(new UserTransaction
                {
                    Id         = Guid.NewGuid(),
                    AccountId  = fromWithdraw.UserAccountId,
                    CryptoId   = fromWallet.CryptoId,
                    CryptoCode = fromWallet.CryptoCode,
                    Type       = UserTransactionType.Withdrawal,
                    DetailId   = fromWithdraw.Id.ToString(),
                    Status     = (byte)fromWithdraw.Status,
                    Timestamp  = fromWithdraw.Timestamp,
                    Amount     = fromWithdraw.Amount,
                    OrderNo    = fromWithdraw.OrderNo
                });

                var fromWithdrawFee = new UserWithdrawalFee
                {
                    Amount       = fromWithdraw.Amount,
                    WithdrawalId = fromWithdraw.Id,
                    Fee          = fromWithdraw.Amount *
                                   Convert.ToDecimal(mastSettings.First(e => e.Name == "UserWithdrawal_ToUser").Value),
                    Timestamp = DateTime.UtcNow
                };

                new UserWithdrawalFeeDAC().Create(fromWithdrawFee);

                new UserWalletDAC().Decrease(fromWallet.Id, fromWithdraw.Amount);

                new UserWalletStatementDAC().Insert(new UserWalletStatement
                {
                    WalletId      = fromWallet.Id,
                    Action        = MerchantWalletStatementAction.Withdrawal,
                    Amount        = -fromWithdraw.Amount,
                    Balance       = fromWallet.Balance - fromWithdraw.Amount,
                    FrozenAmount  = 0,
                    FrozenBalance = fromWallet.FrozenBalance,
                    Timestamp     = DateTime.UtcNow
                });

                //充币
                var amount = fromWithdraw.Amount - fromWithdrawFee.Fee;
                if (amount <= 0)
                {
                    throw new CommonException(ReasonCode.GENERAL_ERROR, MessageResources.ArrivalAmountError);
                }

                new UserWalletDAC().Increase(toWallet.Id, amount);
                new UserWalletStatementDAC().Insert(new UserWalletStatement
                {
                    WalletId      = toWallet.Id,
                    Action        = UserWalletStatementAction.Deposit,
                    Amount        = amount,
                    Balance       = toWallet.Balance + amount,
                    FrozenAmount  = 0,
                    FrozenBalance = toWallet.FrozenBalance,
                    Timestamp     = DateTime.UtcNow
                });

                model = new UserDepositDAC().Insert(new UserDeposit
                {
                    UserAccountId = toWallet.UserAccountId,
                    UserWalletId  = toWallet.Id,
                    FromAddress   = fromWallet.Address,
                    FromTag       = fromWallet.Tag,
                    ToAddress     = toWallet.Address,
                    ToTag         = toWallet.Tag,
                    Amount        = amount,
                    Status        = TransactionStatus.Confirmed,
                    Timestamp     = DateTime.UtcNow,
                    OrderNo       = IdentityHelper.OrderNo(),
                    TransactionId = fromWallet.UserAccountId.ToString("N"),
                    SelfPlatform  = true,
                    CryptoCode    = fromWallet.CryptoCode
                });
                new UserTransactionDAC().Insert(new UserTransaction
                {
                    Id         = Guid.NewGuid(),
                    AccountId  = model.UserAccountId,
                    CryptoId   = fromWallet.CryptoId,
                    CryptoCode = fromWallet.CryptoCode,
                    Type       = UserTransactionType.Deposit,
                    DetailId   = model.Id.ToString(),
                    Status     = (byte)model.Status,
                    Timestamp  = model.Timestamp,
                    Amount     = model.Amount,
                    OrderNo    = model.OrderNo
                });

                scope.Complete();
            }

            UserMSMQ.PubUserWithdrawCompleted(fromWithdraw.Id, 0);
            UserMSMQ.PubUserDeposit(model.Id, 0);

            return(new WithdrawOM
            {
                OrderId = fromWithdraw.Id,
                OrderNo = fromWithdraw.OrderNo,
                Timestamp = fromWithdraw.Timestamp.ToUnixTime().ToString()
            });
        }
        public WithdrawOM Withdraw(UserAccount user, WithdrawIM im, string clientIP)
        {
            SecurityVerify.Verify <WithdrawVerify>(new CustomVerifier("UserWithdraw"), SystemPlatform.FiiiPay, user.Id.ToString(), (model) =>
            {
                return(model.PinVerified && model.CombinedVerified);
            });


            if (user.L1VerifyStatus != VerifyStatus.Certified)
            {
                throw new CommonException(ReasonCode.NOT_VERIFY_LV1, Resources.EMNeedLV1Verfied);
            }

            var cryptocurrency = new CryptocurrencyDAC().GetById(im.CoinId);

            if (!cryptocurrency.Status.HasFlag(CryptoStatus.Withdrawal) || cryptocurrency.Enable == 0)
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, MessageResources.CurrencyForbidden);
            }

            CryptoAddressValidation.ValidateAddress(cryptocurrency.Code, im.Address);
            if (!string.IsNullOrEmpty(im.Tag))
            {
                CryptoAddressValidation.ValidateTag(cryptocurrency.Code, im.Tag);
            }
            //else if (cryptocurrency.NeedTag)
            //{
            //    throw new CommonException(ReasonCode.NEED_INPUT_TAG, GeneralResources.EMNeedInputTag);
            //}

            if (im.Amount <= 0)
            {
                throw new ApplicationException(MessageResources.AmountGreater);
            }

            var IsAllowWithdrawal = user.IsAllowWithdrawal ?? true;

            if (!IsAllowWithdrawal)
            {
                throw new CommonException(ReasonCode.Not_Allow_Withdrawal, MessageResources.WithdrawalDisabled);
            }

            var fromWallet = new UserWalletDAC().GetByAccountId(user.Id, im.CoinId);


            //var profile = new UserProfileAgent().GetUserProfile(user.Id);

            //标准化这个金额,防止超过8位
            im.Amount = im.Amount.ToSpecificDecimal(cryptocurrency.DecimalPlace);

            var mastSettings = new MasterSettingDAC().SelectByGroup("UserWithdrawal");

            var Withdrawal_PerTx_Limit_User_NotVerified    = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerTx_Limit_User_NotVerified").Value);
            var Withdrawal_PerDay_Limit_User_NotVerified   = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerDay_Limit_User_NotVerified").Value);
            var Withdrawal_PerMonth_Limit_User_NotVerified = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerMonth_Limit_User_NotVerified").Value);

            var Withdrawal_PerTx_Limit_User_Lv1Verified    = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerTx_Limit_User_Lv1Verified").Value);
            var Withdrawal_PerDay_Limit_User_Lv1Verified   = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerDay_Limit_User_Lv1Verified").Value);
            var Withdrawal_PerMonth_Limit_User_Lv1Verified = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerMonth_Limit_User_Lv1Verified").Value);

            var Withdrawal_PerTx_Limit_User_Lv2Verified    = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerTx_Limit_User_Lv2Verified").Value);
            var Withdrawal_PerDay_Limit_User_Lv2Verified   = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerDay_Limit_User_Lv2Verified").Value);
            var Withdrawal_PerMonth_Limit_User_Lv2Verified = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerMonth_Limit_User_Lv2Verified").Value);

            var MinAmount = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_MinAmount").Value);

            var merchantWalletDac = new MerchantWalletDAC();
            var userWalletDac     = new UserWalletDAC();

            var isWithdrawToInside = (merchantWalletDac.IsMerchantWalletAddress(im.Address) || userWalletDac.IsUserWalletAddress(im.Address));

            if (isWithdrawToInside)
            {
                MinAmount = Convert.ToDecimal(mastSettings.First(e => e.Name == "UserWithdrawal_ToUser_MinAmount").Value);
            }

            var exchangeRate = GetMarketPrice(user.CountryId, cryptocurrency.Code, "USD");

            var _minAmount = (MinAmount / exchangeRate).ToSpecificDecimal(cryptocurrency.DecimalPlace);

            if (im.Amount < _minAmount)
            {
                throw new ApplicationException(MessageResources.MinWidrawalError);
            }

            var     withdrawalDAC     = new UserWithdrawalDAC();
            var     today             = DateTime.UtcNow.Date;
            decimal dailyWithdrawal   = withdrawalDAC.DailyWithdrawal(user.Id, im.CoinId, today);
            decimal monthlyWithdrawal = withdrawalDAC.MonthlyWithdrawal(user.Id, im.CoinId, new DateTime(today.Year, today.Month, 1));

            var PerDayLimit   = 0M;
            var PerMonthLimit = 0M;

            if (user.L1VerifyStatus == VerifyStatus.Certified && user.L2VerifyStatus == VerifyStatus.Certified)
            {
                PerDayLimit   = Withdrawal_PerDay_Limit_User_Lv2Verified;
                PerMonthLimit = Withdrawal_PerMonth_Limit_User_Lv2Verified;
            }
            else if (user.L1VerifyStatus == VerifyStatus.Certified && user.L2VerifyStatus != VerifyStatus.Certified)
            {
                PerDayLimit   = Withdrawal_PerDay_Limit_User_Lv1Verified;
                PerMonthLimit = Withdrawal_PerMonth_Limit_User_Lv1Verified;
            }
            else if (user.L1VerifyStatus != VerifyStatus.Certified && user.L2VerifyStatus != VerifyStatus.Certified)
            {
                PerDayLimit   = Withdrawal_PerDay_Limit_User_NotVerified;
                PerMonthLimit = Withdrawal_PerMonth_Limit_User_NotVerified;
            }
            if ((PerDayLimit / exchangeRate - dailyWithdrawal).ToSpecificDecimal(cryptocurrency.DecimalPlace) < im.Amount)
            {
                throw new ApplicationException(MessageResources.TodayWidrawalLimit);
            }
            if ((PerMonthLimit / exchangeRate - monthlyWithdrawal).ToSpecificDecimal(cryptocurrency.DecimalPlace) < im.Amount)
            {
                throw new ApplicationException(MessageResources.MonthWithdrawalLimit);
            }

            var fromWithdraw = new UserWithdrawal
            {
                UserAccountId = user.Id,
                UserWalletId  = fromWallet.Id,
                Address       = im.Address,
                Tag           = im.Tag,
                Amount        = im.Amount,
                Status        = TransactionStatus.UnSubmit,
                Timestamp     = DateTime.UtcNow,
                OrderNo       = IdentityHelper.OrderNo(),
                CryptoCode    = fromWallet.CryptoCode,
                CryptoId      = fromWallet.CryptoId
            };

            //是否是商户地址
            var toMerchantWallet = merchantWalletDac.GetByAddressAndCrypto(im.CoinId, im.Address, im.Tag);

            if (toMerchantWallet != null)
            {
                //if (toMerchantWallet.CryptoId != im.CoinId)
                //    throw new CommonException(ReasonCode.GENERAL_ERROR, GeneralResources.EMInvalidAddress);
                //return WithdrawalToMerchantAccount(fromWallet, fromWithdraw, fromWithdrawFee, toMerchantWallet, cryptocurrency);
                //042018
                throw new CommonException(ReasonCode.CAN_NOT_WITHDRAW_TO_FiiiPOS, MessageResources.FiiiPayCantWithdrawToFiiiPOS);
            }

            //是否是用户地址
            var toUserWallet = userWalletDac.GetByAddressAndCrypto(im.CoinId, im.Address, im.Tag);

            if (toUserWallet != null)
            {
                if (toUserWallet.UserAccountId == user.Id)
                {
                    throw new CommonException(ReasonCode.CANNOT_TRANSFER_TO_YOURSELF, MessageResources.WithdrawalToSelfError);
                }

                var toFiiiPayMinWithdrawAmount = GetToFiiiPayMinAmount(Convert.ToDecimal(mastSettings.First(e => e.Name == "UserWithdrawal_ToUser_MinAmount").Value), exchangeRate, cryptocurrency.DecimalPlace);
                if (im.Amount < toFiiiPayMinWithdrawAmount)
                {
                    throw new CommonException(10000, MessageResources.MinWidrawalError);
                }

                return(WithdrawalToUserAccount(fromWallet, fromWithdraw, toUserWallet));
            }

            var tier = cryptocurrency.Withdrawal_Tier ?? 0;
            var fee  = im.Amount * tier + (cryptocurrency.Withdrawal_Fee ?? 0);

            fee = fee.ToSpecificDecimal(cryptocurrency.DecimalPlace);
            var actualAmount = im.Amount - fee;

            if (fromWallet.Balance < im.Amount)
            {
                throw new CommonException(ReasonCode.INSUFFICIENT_BALANCE, MessageResources.InsufficientBalance);
            }
            if (actualAmount <= 0)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, MessageResources.ArrivalAmountError);
            }

            //地址是FiiiPay的地址,但tag找不到
            if (cryptocurrency.NeedTag && isWithdrawToInside)
            {
                return(CancelWithdrawal(fromWithdraw));
            }

            ILog _logger = LogManager.GetLogger("LogicError");

            //如果都不是,向Finance申请提现

            //var agent = new FiiiFinanceAgent();

            var requestModel = new CreateWithdrawModel
            {
                AccountID        = user.Id,
                AccountType      = AccountTypeEnum.User,
                CryptoName       = cryptocurrency.Code,
                ReceivingAddress = im.Address,
                DestinationTag   = im.Tag,
                Amount           = actualAmount,
                IPAddress        = clientIP,
                TransactionFee   = fee
            };

            using (var scope = new TransactionScope())
            {
                try
                {
                    fromWithdraw.Id = withdrawalDAC.Create(fromWithdraw);
                    var fromWithdrawFee = new UserWithdrawalFee
                    {
                        Amount       = im.Amount,
                        Fee          = fee,
                        Timestamp    = DateTime.UtcNow,
                        WithdrawalId = fromWithdraw.Id
                    };

                    new UserTransactionDAC().Insert(new UserTransaction
                    {
                        Id         = Guid.NewGuid(),
                        AccountId  = fromWithdraw.UserAccountId,
                        CryptoId   = fromWithdraw.CryptoId,
                        CryptoCode = fromWithdraw.CryptoCode,
                        Type       = UserTransactionType.Withdrawal,
                        DetailId   = fromWithdraw.Id.ToString(),
                        Status     = (byte)fromWithdraw.Status,
                        Timestamp  = fromWithdraw.Timestamp,
                        Amount     = fromWithdraw.Amount,
                        OrderNo    = fromWithdraw.OrderNo
                    });

                    new UserWithdrawalFeeDAC().Create(fromWithdrawFee);

                    userWalletDac.Freeze(fromWallet.Id, im.Amount);

                    new UserWalletStatementDAC().Insert(new UserWalletStatement
                    {
                        WalletId      = fromWallet.Id,
                        Action        = UserWalletStatementAction.Withdrawal,
                        Amount        = 0 - im.Amount,
                        Balance       = fromWallet.Balance - im.Amount,
                        FrozenAmount  = im.Amount,
                        FrozenBalance = fromWallet.FrozenBalance + im.Amount,
                        Timestamp     = DateTime.UtcNow
                    });

                    requestModel.WithdrawalId = fromWithdraw.Id;
                    Framework.Queue.RabbitMQSender.SendMessage("WithdrawSubmit", requestModel);

                    scope.Complete();
                }
                catch (CommonException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    _logger.Info($"Withdraw CreateWithdrawRequest faild.WithdrawID:{fromWithdraw.Id},OrderNo:{fromWithdraw.OrderNo}.request Parameter - {requestModel}. Error message:{ex.Message}");
                    throw;
                }
            }

            return(new WithdrawOM
            {
                OrderId = fromWithdraw.Id,
                OrderNo = fromWithdraw.OrderNo,
                Timestamp = fromWithdraw.Timestamp.ToUnixTime().ToString()
            });
        }
        public async Task Handle(Chat chat, int chatUserId, double amount)
        {
            var walletUser  = GetWallet(chatUserId);
            var userBalance = await _userBalanceRepository.Get(chatUserId);

            if (userBalance.Balance < amount)
            {
                await _botService.SendTextMessage(chat.Id,
                                                  string.Format(ReplyConstants.InsufficientBalance, userBalance.Balance.RoundMetahashHash(), amount.RoundMetahashHash()));
            }
            else
            {
                if (walletUser != null)
                {
                    var walletAddress = walletUser.PartitionKey;

                    try
                    {
                        // get previous withdrawals and see if they completed. We do this in case the network sends a failed transaction and would still complete after 10 minutes.
                        var lastWithdrawal = _withdrawalRepository.GetByUserId(walletUser.GetUserId().GetValueOrDefault());

                        if (lastWithdrawal != null && lastWithdrawal.StartDate > DateTime.UtcNow.AddMinutes(-15) && lastWithdrawal.State != WithdrawalState.Completed)
                        {
                            _logger.LogInformation($"Retrying to verify Tx {lastWithdrawal.TxId}");
                            var isSuccess = await VerifyTx(lastWithdrawal.TxId, lastWithdrawal);

                            _logger.LogInformation($"Verify Tx {lastWithdrawal.TxId} result is {isSuccess}");
                            await SetWithdrawalState(isSuccess, lastWithdrawal, chat.Id, chatUserId, amount, lastWithdrawal.TxId);
                        }
                        else
                        {
                            if (lastWithdrawal != null && lastWithdrawal.StartDate > DateTime.UtcNow.AddHours(-4))
                            {
                                _logger.LogInformation($"Withdrawal denied for user {chatUserId}. Only 1 withdrawal is allowed every 4h.");

                                await _botService.SendTextMessage(chat.Id, ReplyConstants.WithdrawLimit);
                            }
                            else
                            {
                                var userWithdrawal = new UserWithdrawal(chatUserId)
                                {
                                    WalletAddress = walletAddress, Amount = amount, State = WithdrawalState.Created, StartDate = DateTime.UtcNow
                                };
                                await _withdrawalRepository.AddOrUpdate(userWithdrawal);

                                var transactionId = await _nodeExecutionService.Withdraw(walletAddress, amount);

                                if (!string.IsNullOrEmpty(transactionId))
                                {
                                    userWithdrawal.TxId  = transactionId;
                                    userWithdrawal.State = WithdrawalState.Verification;
                                    await _withdrawalRepository.AddOrUpdate(userWithdrawal);

                                    await _botService.SendTextMessage(chat.Id, ReplyConstants.WithdrawVerification);

                                    // make sure network is up to date
                                    System.Threading.Thread.Sleep(5000);

                                    if (!await VerifyTx(transactionId, userWithdrawal))
                                    {
                                        await _botService.SendTextMessage(chat.Id, ReplyConstants.WithdrawVerificationLonger);

                                        // make sure network is up to date
                                        System.Threading.Thread.Sleep(20000);

                                        var isSuccess = await VerifyTx(transactionId, userWithdrawal);
                                        await SetWithdrawalState(isSuccess, userWithdrawal, chat.Id, chatUserId, amount, transactionId);
                                    }
                                    else
                                    {
                                        await SetWithdrawalSuccess(userWithdrawal, chat.Id, chatUserId, amount, transactionId);
                                    }
                                }
                                else
                                {
                                    userWithdrawal.State = WithdrawalState.Failed;
                                    await _withdrawalRepository.AddOrUpdate(userWithdrawal);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogCritical(
                            $"Withdrawal failed for userId: {chatUserId} and wallet: {walletAddress} for amount: {amount}",
                            ex);

                        await _botService.SendTextMessage(chat.Id, ReplyConstants.UnableToWithdraw);
                    }
                }
            }
        }
Beispiel #13
0
 public async Task AddOrUpdate(UserWithdrawal transaction)
 {
     await _tableStorageService.InsertOrMergeEntity(TableName, transaction);
 }