private async Task <string> SendTransaction(PrizePayment prizePayment) { try { var connector = new WalletConnector ( prizePayment.Host, prizePayment.UserName, prizePayment.Password ); var result = await connector.SendToAddressAsync(prizePayment.Destination, decimal.Parse(prizePayment.Amount)); return(result.Txid); } catch (Exception ex) { Log.Exception("Failed to send transaction.", ex); return(null); } }
private async Task PerformWalletTransactionsAndUpdateDepositsWithIds(List <string> transactionIds, IExchangeDataContext context) { Log.Message(LogLevel.Info, "PerformWalletTransactionsAndUpdateDepositsWithIds entered."); // send transactions to the wallets for System_User cefs payments and update the deposits with the real txId. var cefsDeposits = await context.Deposit.Where(x => transactionIds.Contains(x.Txid)).ToListAsync().ConfigureAwait(false); foreach (var txId in transactionIds) { try { var deposit = cefsDeposits.FirstOrDefault(x => x.Txid == txId); var currency = await context.Currency.FirstOrDefaultAsync(c => c.Id == deposit.CurrencyId).ConfigureAwait(false); var currencyAddress = await context.Address.FirstOrDefaultAsync(a => a.UserId == Constant.SYSTEM_USER_STAGING && a.CurrencyId == deposit.CurrencyId).ConfigureAwait(false); if (currencyAddress == null) { Log.Message(LogLevel.Error, $"No address exists for currency {currency.Symbol}. Unable to process CEF deposit."); continue; } var connector = new WalletConnector(currency.WalletHost, currency.WalletPort, currency.WalletUser, currency.WalletPass, WALLET_TIMEOUT); var result = await connector.SendToAddressAsync(currencyAddress.AddressHash, deposit.Amount); if (result != null) { deposit.Txid = result.Txid; await context.SaveChangesAsync(); } } catch (Exception ex) { Log.Message(LogLevel.Error, $"Wallet Transaction blew up.\r\n{ex.Message}"); } } Log.Message(LogLevel.Info, "PerformWalletTransactionsAndUpdateDepositsWithIds exited."); }
/// <summary> /// Processes the withrawals. /// </summary> /// <returns></returns> private async Task ProcessWithrawals() { using (var dataAccess = new MsSqlDataAccess()) using (var balanceRepo = new Repository <Balance>()) using (var currencyRepo = new Repository <Currency>()) { var start = DateTime.Now; Log.Message(LogLevel.Info, "[ProcessWithrawals] - Processing pending withdrawals..."); var pendingWithdraws = GetPendingWithdraws(); if (!pendingWithdraws.Any()) { Log.Message(LogLevel.Info, "[ProcessWithrawals] - No pending withdraws found."); return; } Log.Message(LogLevel.Info, "[ProcessWithrawals] - {0} pending withdraws found, Processing...", pendingWithdraws.Count); foreach (var currency in await currencyRepo.GetAllAsync(x => x.IsEnabled)) { if (!_isEnabled) { return; } try { Log.Message(LogLevel.Info, "[ProcessWithrawals] - Processing pending withdraws for {0}...", currency.Symbol); if (!IsWalletOnline(currency.Status)) { Log.Message(LogLevel.Info, "[ProcessWithrawals] - {0} wallet current status is '{1}', skipping.", currency.Symbol, currency.Status); continue; } var wallet = new WalletConnector(currency.WalletHost, currency.WalletPort, currency.WalletUser, currency.WalletPass, 60000 * 4); var withdraws = pendingWithdraws.Where(x => x.CurrencyId == currency.Id); if (withdraws.IsNullOrEmpty()) { Log.Message(LogLevel.Info, "[ProcessWithrawals] - No pending withdraws found for {0}...", currency.Symbol); continue; // next coin } foreach (var withdraw in withdraws) { Log.Message(LogLevel.Info, "[ProcessWithrawals] - Processing withdraw #{0}...", withdraw.Id); try { //await SendNotification(withdraw.UserId, "Processing {0} withdraw #{1}, {2}{0}", currency.Symbol, withdraw.Id, withdraw.Amount.ToString("F8")); //Run a balance order to ensure we have the correct balance information if (!await AuditUserBalance(dataAccess, withdraw.UserId, withdraw.CurrencyId)) { continue; } // get the users balance information has enough in locked in pending var balance = await balanceRepo.GetOrDefaultAsync(x => x.UserId == withdraw.UserId && x.CurrencyId == withdraw.CurrencyId); if (balance == null || balance.Total <= 0) { //await SendErrorNotification(withdraw.UserId, "{0} withdraw #{1}, Insufficient funds.", currency.Symbol, withdraw.Id); LogError("ProcessWithrawals", "Withdraw Failed, {0} withdraw #{1}, Insufficient funds.", currency.Symbol, withdraw.Id); continue; } if (balance.Total < withdraw.Amount || balance.PendingWithdraw < withdraw.Amount || balance.PendingWithdraw > balance.Total) { //await SendErrorNotification(withdraw.UserId, "{0} withdraw #{1}, Insufficient funds.", currency.Symbol, withdraw.Id); LogError("ProcessWithrawals", "Withdraw Failed, {0} withdraw #{1}, Insufficient funds.", currency.Symbol, withdraw.Id); continue; } // again check if its a valid address if (!await wallet.ValidateAddressAsync(withdraw.Address)) { LogError("ProcessWithrawals", "Withdraw Failed, Invalid {0} address, WithdrawId: {1}", currency.Symbol, withdraw.Id); continue; } //decimal amountExcludingFees = currency.WithdrawFeeType == WithdrawFeeType.Normal // ? withdraw.Amount - currency.WithdrawFee // : withdraw.Amount - ((withdraw.Amount / 100m) * currency.WithdrawFee); decimal withdrawFee = GetWithdrawFee(wallet, currency, withdraw.Amount); decimal amountExcludingFees = withdraw.Amount - withdrawFee; var withdrawResult = await wallet.SendToAddressAsync(withdraw.Address, amountExcludingFees); if (withdrawResult == null || string.IsNullOrEmpty(withdrawResult.Txid)) { LogError("ProcessWithrawals", "Withdraw Failed, Failed to send {0} transaction, WithdrawId: {1}", currency.Symbol, withdraw.Id); continue; } // Update the withdraw with the txid and set to completed if (await dataAccess.ExecuteAsync("WalletSetWithdrawTxId", new { WithdrawId = withdraw.Id, TxId = withdrawResult.Txid }, CommandType.StoredProcedure) <= 0) { LogError("ProcessWithrawals", "Withdraw Failed, Failed to update {0} withdraw transaction id, WithdrawId: {1}, TxId: {2}", currency.Symbol, withdraw.Id, withdrawResult.Txid); continue; } //Run a balance audit to ensure we have the correct balance information if (!await AuditUserBalance(dataAccess, withdraw.UserId, withdraw.CurrencyId)) { continue; } //await SendNotification(withdraw.UserId, "{0} withdrawal #{1} successfully processed.", currency.Symbol, withdraw.Id); //await SendBalanceNotification(withdraw.UserId, currency.Id, currency.Symbol); } catch (Exception ex) { LogError(ex, "ProcessWithrawals", "An exception occured processing Currency: {0}, WithdrawId: {1}", ex, currency.Symbol, withdraw.Id); continue; } Log.Message(LogLevel.Info, "[ProcessWithrawals] - Processing withdraw #{0} complete.", withdraw.Id); } } catch (Exception ex) { LogError(ex, "ProcessWithrawals", "An exception occured processing Currency: {0}", ex, currency.Symbol); continue; } Log.Message(LogLevel.Info, "[ProcessWithrawals] - Processing pending withdraws for {0} complete.", currency.Symbol); } Log.Message(LogLevel.Info, "[ProcessWithrawals] - Processing pending withdrawals complete. Elapsed: {0}", DateTime.Now - start); } }
private async Task ProcessTransactions() { Log.Message(LogLevel.Info, "[ProcessNZDT] - Processing NZDT Transactions..."); List <NzdtTransaction> nzdtTransactions; using (var context = ExchangeDataContextFactory.CreateContext()) { nzdtTransactions = await context.NzdtTransaction .Where(x => x.TransactionStatus == NzdtTransactionStatus.ReadyForProcessing) .Where(x => DbFunctions.AddHours(x.CreatedOn, 1) <= DateTime.UtcNow) .ToListNoLockAsync(); Log.Message(LogLevel.Info, $"[ProcessNZDT] - {nzdtTransactions.Count()} transactions found, processing..."); foreach (var transaction in nzdtTransactions) { transaction.TransactionStatus = NzdtTransactionStatus.Processed; } await context.SaveChangesAsync(); } var wallet = new WalletConnector(_nzdtAssetWalletIp, _nzdtAssetWalletPort, _nzdtAssetWalletUserName, _nzdtAssetWalletPassword, 30000); foreach (var transaction in nzdtTransactions) { try { var sendResult = await wallet.SendToAddressAsync(Constant.NzdtBaseExchangeAddress, transaction.Amount); using (var context = ExchangeDataContextFactory.CreateContext()) { var deposit = new Deposit { Txid = string.IsNullOrEmpty(sendResult?.Txid) ? $"{transaction.Id}" : sendResult.Txid, Amount = transaction.Amount, TimeStamp = DateTime.UtcNow, CurrencyId = Constant.NZDT_ID, Status = DepositStatus.Confirmed, Confirmations = 20, UserId = transaction.UserId.Value, Type = DepositType.Normal }; var tx = await context.NzdtTransaction.FirstNoLockAsync(x => x.Id == transaction.Id); tx.Deposit = deposit; await context.SaveChangesAsync(); await context.AuditUserBalance(transaction.UserId.Value, Constant.NZDT_ID); await context.SaveChangesAsync(); } } catch (Exception ex) { Log.Exception($"[ProcessNZDT] Insert Deposit failed for transaction {transaction.Id}", ex); } } Log.Message(LogLevel.Info, $"[ProcessNZDT] - Processing NZDT Transactions complete."); }
private async Task SendWithdrawals(IDataContext context, Currency currency) { try { Log.Message(LogLevel.Info, "Sending pending {0} withdrawals...", currency.Symbol); if (currency.Status == CurrencyStatus.Maintenance || currency.Status == CurrencyStatus.Offline) { return; // currency is skipped } var connector = new WalletConnector(currency.WalletHost, currency.WalletPort, currency.WalletUser, currency.WalletPass); var pendingWithdraws = await context.Withdraw.Where(x => x.CurrencyId == currency.Id && x.WithdrawStatus == WithdrawStatus.Pending && x.User.IsWithdrawEnabled).ToListAsync(); foreach (var pendingWithdraw in pendingWithdraws) { pendingWithdraw.WithdrawStatus = WithdrawStatus.Processing; } await context.SaveChangesAsync(); if (!pendingWithdraws.Any()) { Log.Message(LogLevel.Info, "No pending {0} withdrawals found.", currency.Symbol); return; } foreach (var pendingWithdraw in pendingWithdraws) { try { Log.Message(LogLevel.Info, "Processing pending withdrawal. Currency: {0}, Amount: {1}, Address: {2}", currency.Symbol, pendingWithdraw.Amount, pendingWithdraw.Address); var auditResult = await AuditUser(context, pendingWithdraw.CurrencyId, pendingWithdraw.UserId); if (!auditResult.Success) { Log.Message(LogLevel.Error, "Failed to audit user balance. Currency: {0}, User: {1}", currency.Symbol, pendingWithdraw.UserId); continue; } if (auditResult.Total <= 0 || auditResult.Total < pendingWithdraw.Amount || auditResult.PendingWithdraw < pendingWithdraw.Amount || auditResult.PendingWithdraw > auditResult.Total) { Log.Message(LogLevel.Error, "User has insufficiant funds for withdraw: Currency:{0}, User: {1}", currency.Symbol, pendingWithdraw.UserId); continue; } decimal withdrawFee = GetWithdrawFee(currency, pendingWithdraw.Amount); decimal amountExcludingFees = pendingWithdraw.Amount - withdrawFee; Log.Message(LogLevel.Info, "Sending wallet transaction. Currency: {0}, Host: {1}, Port: {2}", currency.Symbol, currency.WalletHost, currency.WalletPort); var withdrawResult = await connector.SendToAddressAsync(pendingWithdraw.Address, amountExcludingFees); if (withdrawResult == null || string.IsNullOrEmpty(withdrawResult.Txid)) { Log.Message(LogLevel.Error, "Received no response from wallet, CAUTION: Withdraw status unknown!"); continue; } // Update the withdraw with the txid and set to completed pendingWithdraw.Txid = withdrawResult.Txid; pendingWithdraw.WithdrawStatus = WithdrawStatus.Complete; await context.SaveChangesAsync(); Log.Message(LogLevel.Info, "Sending wallet transaction complete. Currency: {0}, TransactionId: {1}", currency.Symbol, withdrawResult.Txid); auditResult = await AuditUser(context, pendingWithdraw.CurrencyId, pendingWithdraw.UserId); await NotificationService.SendBalanceUpdate(GetBalanceNotification(auditResult)); } catch (Exception ex) { Log.Exception("An exception occured sending withdraw", ex); } } Log.Message(LogLevel.Info, "Sending pending {0} withdrawals complete.", currency.Symbol); } catch (Exception ex) { Log.Exception("An exception occured sending withdrawals", ex); } }