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); }