private async Task LogCycleCompleted() { try { using (var context = new MsSqlDataAccess()) { Log.Message(LogLevel.Debug, "[UpdateServerInfo] - Updating timestamp"); int rowAffected = await context.ExecuteAsync(_updateServerInfo, new { LastRunTime = DateTime.UtcNow, Host = _hostname }); if (rowAffected > 0) { Log.Message(LogLevel.Debug, "[UpdateServerInfo] - timestamp updated"); } else { Log.Message(LogLevel.Error, "[UpdateServerInfo] - timestamp update for host: {0} failed", _hostname); } } } catch (Exception ex) { LogError(ex, "[UpdateServerInfo]", "Timestamp update for host: {0} failed", _hostname); } }
/// <summary> /// Audits the user balance. /// </summary> /// <param name="dataAccess">The data access layer.</param> /// <param name="userId">The user identifier.</param> /// <param name="currency">The currency.</param> private async Task <bool> AuditUserBalance(MsSqlDataAccess dataAccess, Guid userId, int currency) { Log.Message(LogLevel.Debug, "[AuditUserBalance] - Auditing user balance for CurrencyId: {0}, UserId: {1}...", currency, userId); if (await dataAccess.ExecuteAsync("AuditUserBalance", new { UserId = userId, CurrencyId = currency }, CommandType.StoredProcedure) > 0) { Log.Message(LogLevel.Debug, "[AuditUserBalance] - Successfully audited user balance for CurrencyId: {0}, UserId: {1}", currency, userId); return(true); } LogError("AuditUserBalance", "Failed to audit user balance, CurrencyId: {0}, UserId: {1}", currency, userId); return(false); }
public static IDataConnection InitDataBase(DbInitData data = null) { if (data == null) { data = DbInit; } switch (data.ProviderName) { case "MsSql": DataConnection = new MsSqlDataAccess(data); break; } return(DataConnection); }
/// <summary> /// Gets all the pending withdraws from the database. /// </summary> private List <WithdrawResult> GetPendingWithdraws() { Log.Message(LogLevel.Debug, "[GetPendingWithdraws] - Getting pending withdrawals.."); using (var dataAccess = new MsSqlDataAccess()) { dataAccess.DataContext.Connection.Open(); using (var dbTransaction = dataAccess.DataContext.Connection.BeginTransaction(System.Data.IsolationLevel.Snapshot)) { dataAccess.DataContext.Transaction = dbTransaction; try { var pendingWithdraws = dataAccess.DataContext.ExecuteQuery <WithdrawResult>("EXEC WalletGetPendingWithdraws").ToList(); if (!pendingWithdraws.Any()) { try { if (dbTransaction != null) { dbTransaction.Rollback(); } } catch { } return(new List <WithdrawResult>()); } dbTransaction.Commit(); Log.Message(LogLevel.Debug, "[GetPendingWithdraws] - Getting pending withdrawals complete."); return(pendingWithdraws); } catch (Exception ex) { try { if (dbTransaction != null) { dbTransaction.Rollback(); } } catch { } LogError(ex, "GetPendingWithdraws", "An exception occured in GetPendingWithdraws"); } } } return(new List <WithdrawResult>()); }
public IDatabaseHandler CreateDatabase() { IDatabaseHandler database = null; switch (connectionStringSettings.ProviderName.ToLower()) { case "system.data.sqlclient": database = new MsSqlDataAccess(connectionStringSettings.ConnectionString); break; case "mysql.data.mysqlclient": database = new MySqlDataAccess(connectionStringSettings.ConnectionString); break; case "npgsql": database = new PostgreSqlDataAccess(connectionStringSettings.ConnectionString); break; default: break; } return(database); }
/// <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 QueryDeposits() { try { using (var context = new MsSqlDataAccess()) using (var userRepo = new Repository <User>()) using (var currencyRepo = new Repository <Currency>()) using (var depositRepo = new Repository <Deposit>()) using (var addressRepo = new Repository <Address>()) { // Cache some data var userTable = userRepo.GetAll().ToListNoLock(); var currencies = currencyRepo.GetAll().Where(x => x.WalletHost == _hostname && x.IsEnabled).ToListNoLock(); var currencyIds = currencies.Select(x => x.Id).ToList(); var addresses = addressRepo.GetAll().Where(x => currencyIds.Contains(x.CurrencyId)).ToListNoLock(); var allDeposits = depositRepo.GetAll().Where(x => currencyIds.Contains(x.CurrencyId)).ToListNoLock(); foreach (var currency in currencies) { if (!_isEnabled) { return; } try { var start = DateTime.Now; Log.Message(LogLevel.Debug, "[QueryDeposits] - Processing Currency: {0}", currency.Symbol); if (!IsWalletOnline(currency.Status)) { Log.Message(LogLevel.Info, "[QueryDeposits] - {0} wallet current status is '{1}', skipping.", currency.Symbol, currency.Status); continue; } // Get everything we need bool updateLastBlockHash = true; string lastBlockHash = currency.LastBlockHash; // Get all transactiosn since the last deposit we confirmed var walletDeposits = GetDeposits(currency); if (!walletDeposits.IsNullOrEmpty()) { Log.Message(LogLevel.Debug, "[QueryDeposits] - {0} deposits found since last block.", walletDeposits.Count()); foreach (var walletDeposit in walletDeposits.OrderBy(x => x.Time)) { if (!_isEnabled) { return; } try { var user = userTable.FirstOrDefault(u => u.Id == GetUserId(walletDeposit.Account)); if (user == null) { var address = addresses.FirstOrDefault(x => x.CurrencyId == currency.Id && x.AddressHash == walletDeposit.Address); if (address == null) { continue; } user = userTable.FirstOrDefault(u => u.Id == address.UserId); if (user == null) { continue; } } // See if it already exists var existingDeposit = allDeposits.FirstOrDefault( x => x.CurrencyId == currency.Id && x.Txid == walletDeposit.Txid && x.UserId == user.Id); if (existingDeposit == null) { // Insert new deposit Log.Message(LogLevel.Debug, "[QueryDeposits] - New deposit found. TxId: {0}", walletDeposit.Txid); var depositStatus = walletDeposit.Confirmations >= currency.MinConfirmations ? DepositStatus.Confirmed : DepositStatus.UnConfirmed; await InsertDeposit(context, user.Id, currency.Id, walletDeposit, DepositType.Normal, depositStatus); await AuditUserBalance(context, user.Id, currency.Id); Log.Message(LogLevel.Debug, "[QueryDeposits] - New deposit inserted. TxId: {0}", walletDeposit.Txid); if (depositStatus == DepositStatus.Confirmed) { lastBlockHash = walletDeposit.Blockhash; } //await SendBalanceNotification(user.Id, currency.Id, currency.Symbol); continue; } else { // Chech confirmations for the unconfirmed deposits if (existingDeposit.DepositStatus == DepositStatus.UnConfirmed) { if (existingDeposit.Confirmations == walletDeposit.Confirmations) { continue; } // Update and check if confirmed Log.Message(LogLevel.Debug, "[QueryDeposits] - Updating deposit confirmations. DepositId: {0}", existingDeposit.Id); if (existingDeposit.Confirmations >= currency.MinConfirmations) { Log.Message(LogLevel.Debug, "[QueryDeposits] - Confirming Deposit. DepositId: {0}", existingDeposit.Id); // Depoist is now confirmed, update syatus and notify user await UpdateDeposit(context, existingDeposit.Id, walletDeposit.Confirmations, DepositStatus.Confirmed); await AuditUserBalance(context, user.Id, currency.Id); //await SendNotification(new WalletNotification(user.Id, string.Format("Deposit #{0} Confirmed", existingDeposit.Id), string.Format("{0} {1} has been added to your balance.", existingDeposit.Amount, currency.Symbol))); //await SendBalanceNotification(user.Id, currency.Id, currency.Symbol); lastBlockHash = walletDeposit.Blockhash; Log.Message(LogLevel.Debug, "[QueryDeposits] - Deposit confirmed. DepositId: {0}", existingDeposit.Id); continue; } await UpdateDeposit(context, existingDeposit.Id, walletDeposit.Confirmations, DepositStatus.UnConfirmed); continue; } } } catch (Exception ex) { // dont update the block hash on error so we can try pick up the errord deposit next poll updateLastBlockHash = false; LogError(ex, "QueryDeposits", "Failed to process deposit, Currency: {0}, TxId: {1}", currency.Symbol, walletDeposit.Txid); } } } // Update the last block we processed if (updateLastBlockHash && lastBlockHash != currency.LastBlockHash) { Log.Message(LogLevel.Debug, "[QueryDeposits] - Updating currency last block hash: {0}", lastBlockHash); await UpdateLastBlockHash(context, currency.Id, lastBlockHash); } Log.Message(LogLevel.Debug, "[QueryDeposits] - Processing Currency: {0} complete. Elapsed {1}", currency.Symbol, DateTime.Now - start); } catch (Exception ex) { LogError(ex, "QueryDeposits", "Failed to query currency for deposits, Currency: {0}", currency.Symbol); } } } } catch (Exception ex) { LogError(ex, "QueryDeposits", "Failed to query deposits"); } }