private async Task InternalBalanceCheck() { try { var balance = await _paymentService.GetMainAccountBalance(); if (balance < _settings.MainAccountMinBalance) { if ((DateTime.UtcNow - _lastWarningSentTime).TotalHours > 1) { string message = $"Main account {_settings.EthereumMainAccount} balance is less that {_settings.MainAccountMinBalance} ETH !"; await _logger.WriteWarningAsync("GenerateUserContractPoolFunction", "InternalBalanceCheck", "", message); await _emailNotifier.WarningAsync("Chronobank integration", message); await _slackNotifier.FinanceWarningAsync(message); _lastWarningSentTime = DateTime.UtcNow; } } } catch (Exception e) { await _logger.WriteErrorAsync("GenerateUserContractPoolFunction", "InternalBalanceCheck", "", e); } }
private async Task SendBalanceNotifications(string asset, string hotWallet, decimal minBalance) { string message = $"Offchain wallet {hotWallet} {asset} balance is less than {minBalance} {asset}!"; await _logger.WriteWarningAsync("GenerateOffchainOutputsFunction", "SendBalanceNotifications", "", message); await _slackNotifier.FinanceWarningAsync(message); await _emailNotifier.WarningAsync("Bitcoin job", message); }
private async Task GenerateFeeOutputs() { await _logger.WriteInfoAsync("GenerateOutputsFunction", "GenerateFeeOutputs", null, "Start process"); var queue = _pregeneratedOutputsQueueFactory.CreateFeeQueue(); try { while (await queue.Count() < _baseSettings.MinPregeneratedOutputsCount) { var uncoloredOutputs = await _bitcoinOutputsService.GetUncoloredUnspentOutputs(_baseSettings.HotWalletForPregeneratedOutputs); var outputs = uncoloredOutputs.ToList(); var totalRequiredAmount = Money.FromUnit(_baseSettings.GenerateOutputsBatchSize * _baseSettings.PregeneratedFeeAmount, MoneyUnit.BTC); // Convert to satoshi var feeAmount = new Money(_baseSettings.PregeneratedFeeAmount, MoneyUnit.BTC); if (outputs.Sum(o => o.TxOut.Value) < totalRequiredAmount) { throw new BackendException($"The sum of total applicable outputs is less than the required: {totalRequiredAmount} satoshis.", ErrorCode.NotEnoughBitcoinAvailable); } var hotWallet = new BitcoinPubKeyAddress(_baseSettings.HotWalletForPregeneratedOutputs, _connectionParams.Network); var builder = new TransactionBuilder(); builder.AddCoins(outputs); builder.SetChange(hotWallet); for (var i = 0; i < _baseSettings.GenerateOutputsBatchSize; i++) { builder.Send(new BitcoinPubKeyAddress(_baseSettings.FeeAddress, _connectionParams.Network), feeAmount); } builder.SendFees(await _feeProvider.CalcFeeForTransaction(builder)); var signedHex = await _signatureApiProvider.SignTransaction(builder.BuildTransaction(false).ToHex()); var signedTr = new Transaction(signedHex); var transactionId = Guid.NewGuid(); await _bitcoinClient.BroadcastTransaction(signedTr, transactionId); await queue.EnqueueOutputs(signedTr.Outputs.AsCoins().Where(o => o.TxOut.Value == feeAmount).ToArray()); await FinishOutputs(transactionId, signedTr, hotWallet); } } finally { if (await queue.Count() < _baseSettings.MinPregeneratedOutputsCount && (DateTime.UtcNow - _lastWarningFeeSentTime).TotalHours > 1) { var message = $"Count of fee outputs is less than {_baseSettings.MinPregeneratedOutputsCount}"; await _slackNotifier.FinanceWarningAsync(message); await _emailNotifier.WarningAsync("Bitcoin job", message); _lastWarningFeeSentTime = DateTime.UtcNow; } await _logger.WriteInfoAsync("GenerateOutputsFunction", "GenerateFeeOutputs", null, "End process"); } }