Пример #1
0
        bool ChainWithdrawToCustomer(ApplicationUser brokerUser, BrokerOrder order)
        {
            var asset  = order.AssetReceive;
            var amount = order.AmountReceive;

            var wallet = _walletProvider.GetChain(asset);

            if (wallet == null)
            {
                _logger.LogError($"No chain wallet for {asset}");
                return(false);
            }
            var brokerWalletTag = wallet.GetTag(brokerUser.Id);

            if (brokerWalletTag == null)
            {
                _logger.LogError($"No tag for broker {brokerUser.Id}");
                return(false);
            }

            var via     = new ViaJsonRpc(_settings.AccessHttpUrl);
            var balance = via.BalanceQuery(brokerUser.Exchange.Id, asset);

            // validate amount
            var amountInt    = wallet.StringToAmount(amount.ToString());
            var availableInt = wallet.StringToAmount(balance.Available);

            if (amountInt > availableInt)
            {
                _logger.LogError("broker available balance is too small");
                return(false);
            }
            if (amountInt <= 0)
            {
                _logger.LogError("amount must be greather then or equal to 0");
                return(false);
            }

            var consolidatedFundsTag = _walletProvider.ConsolidatedFundsTag();

            using (var dbtx = wallet.BeginDbTransaction())
            {
                // ensure tag exists
                if (!wallet.HasTag(consolidatedFundsTag))
                {
                    wallet.NewTag(consolidatedFundsTag);
                    wallet.Save();
                }

                // register withdrawal with wallet
                var tag = wallet.GetTag(brokerUser.Id);
                if (tag == null)
                {
                    tag = wallet.NewTag(brokerUser.Id);
                }
                var spend = wallet.RegisterPendingSpend(consolidatedFundsTag, consolidatedFundsTag,
                                                        order.Recipient, amountInt, tag);
                wallet.Save();
                var businessId = spend.Id;

                try
                {
                    // link pending withdrawal to broker order
                    var bow = new BrokerOrderChainWithdrawal {
                        BrokerOrderId = order.Id, SpendCode = spend.SpendCode
                    };
                    _context.BrokerOrderChainWithdrawals.Add(bow);
                    // we save changes here so that we a broker order cannot be processed twice(BrokerOrderChainWithdrawal.BrokerOrderId is unique)
                    _context.SaveChanges();
                }
                catch
                {
                    _logger.LogError($"unable to create BrokerOrderChainWithdrawal object ({order.Id}, {spend.SpendCode}");
                    throw;
                }

                // register withdrawal with the exchange backend
                var negativeAmount = -amount;
                try
                {
                    via.BalanceUpdateQuery(brokerUser.Exchange.Id, asset, "withdraw", businessId, negativeAmount.ToString(), null);
                }
                catch (ViaJsonException ex)
                {
                    _logger.LogError(ex, "Failed to update (withdraw) user balance (xch id: {0}, asset: {1}, businessId: {2}, amount {3}",
                                     brokerUser.Exchange.Id, asset, businessId, negativeAmount);
                    if (ex.Err == ViaError.BALANCE_UPDATE__BALANCE_NOT_ENOUGH)
                    {
                        dbtx.Rollback();
                        _logger.LogError("balance not enough");
                        return(false);
                    }
                    throw;
                }

                dbtx.Commit();
            }

            return(true);
        }