private async Task <ReturnSignResult> GetAndCheckSign(Guid id, string coinAddress, string fromAddress, string toAddress, BigInteger amount, string signFrom) { bool isRobot = string.IsNullOrEmpty(signFrom); int retryCounter = 0; bool isSuccess = false; do { if (isRobot) { signFrom = await GetSign(id, coinAddress, fromAddress, toAddress, amount); } try { ThrowOnWrongSignature(id, coinAddress, fromAddress, toAddress, amount, signFrom); isSuccess = true; } catch (ClientSideException exc) { await _log.WriteErrorAsync("PendingOperationService", "GetAndCheckSign", $" OperationId {id} - Hash {signFrom}", exc, DateTime.UtcNow); await _slackNotifier.ErrorAsync($"We recieved wrong signature! Sign can't be checked: OperationId {id} - {signFrom} - {signFrom.Length}. Do something!"); throw; } catch (Exception e) { await _log.WriteErrorAsync("PendingOperationService", "GetAndCheckSign", $" OperationId {id}", e, DateTime.UtcNow); if (!isRobot) { throw; } retryCounter++; amount++; if (retryCounter > 1) { await _slackNotifier.ErrorAsync($"Dark Magic Happened! Sign can't be checked: OperationId {id} - {signFrom} - {signFrom.Length}"); throw; } await _log.WriteInfoAsync("PendingOperationService", "GetAndCheckSign", $"ID:{id}, Adpater:{coinAddress}, From:{fromAddress}, To:{toAddress}, Amount:{amount}, IsRobotSignature:{isRobot}", "Retry with amount change! Amount here is more on 1 wei than original", DateTime.UtcNow); } } while (!isSuccess && (isRobot && retryCounter < 2)); return(new ReturnSignResult() { Amount = amount, Sign = signFrom, }); }
public async Task <string> GetContractRaw() { Action throwAction = () => { _slackNotifier.ErrorAsync("Chronobank integration! User contract pool is empty!"); throw new BackendException("User contract pool is empty!", ErrorCode.ContractPoolEmpty); }; var message = await _queue.GetRawMessageAsync(); if (message == null) { throwAction(); } await _queue.FinishRawMessageAsync(message); var contract = message.AsString; if (string.IsNullOrWhiteSpace(contract)) { throwAction(); } return(contract); }
public async Task UpdateUserAssignmentFail(string contractAddress, string userAddress, string coinAdapter) { var canBeRestoredInternally = !string.IsNullOrEmpty(userAddress) && userAddress != Constants.EmptyEthereumAddress; var userAssignmentFail = await _userAssignmentFailRepository.GetAsync(contractAddress); if (userAssignmentFail == null) { userAssignmentFail = new UserAssignmentFail() { CanBeRestoredInternally = canBeRestoredInternally, ContractAddress = contractAddress, NotifiedInSlack = false, FailCount = 0 }; } if (userAssignmentFail.FailCount == _attempsBeforeReassign) { if (canBeRestoredInternally) { var message = new TransferContractUserAssignment() { CoinAdapterAddress = coinAdapter, TransferContractAddress = contractAddress, UserAddress = userAddress }; await _queueUserAssignment.PutRawMessageAsync(JsonConvert.SerializeObject(message)); userAssignmentFail.FailCount = 0; } else { if (userAssignmentFail.NotifiedInSlack.HasValue && !userAssignmentFail.NotifiedInSlack.Value) { await _slackNotifier.ErrorAsync($"TransferAddress - {contractAddress}, UserAddress - {userAddress}, " + $"CoinAdapter Address - {coinAdapter} can't be restored internally"); await _userAssignmentFailRepository.SaveAsync(userAssignmentFail); } return; } } else { userAssignmentFail.FailCount++; } await _userAssignmentFailRepository.SaveAsync(userAssignmentFail); }
private async Task MoveToPoisonQueue(IQueueMessage message, string newMessageVersion) { newMessageVersion = newMessageVersion ?? message.AsString; if (_poisonQueueReader == null) { _poisonQueueReader = _queueReaderFactory.Create(_queueName + PoisonSuffix); } await _poisonQueueReader.AddMessageAsync(newMessageVersion); await _queueReader.FinishMessageAsync(message); if (_shouldNotify) { await _slackNotifier.ErrorAsync($"Msg put to {_queueName + PoisonSuffix}, data: {newMessageVersion}"); } }
public async Task <string> GetContractAddress() { var message = await _queue.GetRawMessageAsync(); if (message != null) { await _queue.FinishRawMessageAsync(message); return(message.AsString); } else { await _slackNotifier.ErrorAsync("Ethereum Core Service! Erc20 deposit contract pool is empty!"); throw new ClientSideException(ExceptionType.ContractPoolEmpty, "Erc20 deposit contract pool is empty!"); } }
private async Task CloseMultiCashout(IMultipleCashout currentMultiCashout) { await _multiCashoutRepository.CloseMultiCashout(currentMultiCashout.MultipleCashoutId); await _slackNotifier.ErrorAsync($"Bitcoin: can't broadcast multicashout {currentMultiCashout.MultipleCashoutId}"); }
public void NotifyAboutError() { _slackNotifier.ErrorAsync("Ethereum Core Service! User contract pool is empty!"); throw new ClientSideException(ExceptionType.ContractPoolEmpty, "Transfer contract pool is empty!"); }
public async Task Execute(CoinTransactionMessage transaction, QueueTriggeringContext context) { ICoinTransaction coinTransaction = null; try { bool isTransactionInMemoryPool = await _ethereumTransactionService.IsTransactionInPool(transaction.TransactionHash); if (isTransactionInMemoryPool) { SendMessageToTheQueueEnd(context, transaction, 100, "Transaction is in memory pool"); return; } coinTransaction = await _coinTransactionService.ProcessTransaction(transaction); } catch (Exception ex) { if (ex.Message != transaction.LastError) { await _log.WriteWarningAsync(nameof(AirlinesHotWalletMonitoringTransactionJob), "Execute", $"TrHash: [{transaction.TransactionHash}]", ""); } SendMessageToTheQueueEnd(context, transaction, 200, ex.Message); await _log.WriteErrorAsync(nameof(AirlinesHotWalletMonitoringTransactionJob), "Execute", "", ex); return; } if (coinTransaction == null) { await RepeatOperationTillWin(transaction); await _slackNotifier.ErrorAsync($"Airlines: Transaction with hash {transaction.TransactionHash} has ERROR. RETRY. Address is yet blocked"); } else { if (coinTransaction.ConfirmationLevel >= CoinTransactionService.Level2Confirm) { bool sentToRabbit = await SendCompleteEvent(transaction.TransactionHash, transaction.OperationId, !coinTransaction.Error, context, transaction); if (sentToRabbit) { await _log.WriteInfoAsync(nameof(AirlinesHotWalletMonitoringTransactionJob), "Execute", "", $"Put coin transaction {transaction.TransactionHash} to rabbit queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } else { await _log.WriteInfoAsync(nameof(AirlinesHotWalletMonitoringTransactionJob), "Execute", "", $"Put coin transaction {transaction.TransactionHash} to monitoring queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } if (coinTransaction.Error) { await _slackNotifier.ErrorAsync($"EthereumCoreService: HOTWALLET - Transaction with hash {transaction.TransactionHash} has an Error. Notify Caller about fail!"); } } else { SendMessageToTheQueueEnd(context, transaction, 100); await _log.WriteInfoAsync(nameof(AirlinesHotWalletMonitoringTransactionJob), "Execute", "", $"Put coin transaction {transaction.TransactionHash} to monitoring queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } } }
public async Task Execute(CoinTransactionMessage transaction, QueueTriggeringContext context) { ICoinTransaction coinTransaction = null; try { bool isTransactionInMemoryPool = await _ethereumTransactionService.IsTransactionInPool(transaction.TransactionHash); if (isTransactionInMemoryPool) { SendMessageToTheQueueEnd(context, transaction, 100, "Transaction is in memory pool"); return; } coinTransaction = await _coinTransactionService.ProcessTransaction(transaction); } catch (Exception ex) { if (ex.Message != transaction.LastError) { await _log.WriteWarningAsync("MonitoringCoinTransactionJob", "Execute", $"TrHash: [{transaction.TransactionHash}]", ""); } SendMessageToTheQueueEnd(context, transaction, 200, ex.Message); await _log.WriteErrorAsync("MonitoringCoinTransactionJob", "Execute", "", ex); return; } if ((coinTransaction == null) && (DateTime.UtcNow - transaction.PutDateTime > _broadcastMonitoringPeriodSeconds)) { await RepeatOperationTillWin(transaction); await _slackNotifier.ErrorAsync($"EthereumCoreService: Transaction with hash {transaction.TransactionHash} has no confirmations." + $" Reason - unable to find transaction in txPool and in blockchain within {_broadcastMonitoringPeriodSeconds} seconds"); } else { if (coinTransaction != null && coinTransaction.ConfirmationLevel >= CoinTransactionService.Level2Confirm) { if (!coinTransaction.Error) { bool sentToRabbit = await SendCompletedCoinEvent( transaction.TransactionHash, transaction.OperationId, true, context, transaction); if (sentToRabbit) { await _log.WriteInfoAsync("CoinTransactionService", "Execute", "", $"Put coin transaction {transaction.TransactionHash} to rabbit queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } else { await _log.WriteInfoAsync("CoinTransactionService", "Execute", "", $"Put coin transaction {transaction.TransactionHash} to monitoring queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } } else { ICoinEvent coinEvent = await GetCoinEvent(transaction.TransactionHash, transaction.OperationId, true); await _slackNotifier.ErrorAsync($"EthereumCoreService: Transaction with hash {transaction.TransactionHash} has an Error!({coinEvent.CoinEventType})"); if (coinEvent.CoinEventType == CoinEventType.CashoutStarted || coinEvent.CoinEventType == CoinEventType.CashoutFailed) { if (coinTransaction.ConfirmationLevel >= 2) { //SEND FAILED CASHOUTS EVENTS HERE AND FILL Black LIST await _blackListAddressesRepository.SaveAsync(new BlackListAddress() { Address = coinEvent.ToAddress }); await SendCompletedCoinEvent(transaction.TransactionHash, transaction.OperationId, false, context, transaction); } else { SendMessageToTheQueueEnd(context, transaction, 200, "Did not recieve confirmation level 3 yet"); } return; } else { await RepeatOperationTillWin(transaction); await _slackNotifier.ErrorAsync($"EthereumCoreService: Transaction with hash {transaction.TransactionHash} has an Error. RETRY!({coinEvent.CoinEventType})"); } } } else { SendMessageToTheQueueEnd(context, transaction, 100); await _log.WriteInfoAsync("CoinTransactionService", "Execute", "", $"Put coin transaction {transaction.TransactionHash} to monitoring queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } } }
public async Task Execute(CoinTransactionMessage transaction, QueueTriggeringContext context) { ICoinTransaction coinTransaction = null; try { bool isTransactionInMemoryPool = await _ethereumTransactionService.IsTransactionInPool(transaction.TransactionHash); if (isTransactionInMemoryPool) { SendMessageToTheQueueEnd(context, transaction, 100, "Transaction is in memory pool"); return; } coinTransaction = await _coinTransactionService.ProcessTransaction(transaction); } catch (Exception ex) { if (ex.Message != transaction.LastError) { await _log.WriteWarningAsync(nameof(HotWalletMonitoringTransactionJob), "Execute", $"TrHash: [{transaction.TransactionHash}]", ""); } SendMessageToTheQueueEnd(context, transaction, 200, ex.Message); await _log.WriteErrorAsync(nameof(HotWalletMonitoringTransactionJob), "Execute", "", ex); return; } if (coinTransaction == null || coinTransaction.Error) { await RepeatOperationTillWin(transaction); //await _slackNotifier.ErrorAsync($"EthereumCoreService: Transaction with hash {transaction.TransactionHash} has no confirmations." + // $" Reason - unable to find transaction in txPool and in blockchain within {_broadcastMonitoringPeriodSeconds} seconds"); } else { if (coinTransaction.ConfirmationLevel >= CoinTransactionService.Level2Confirm) { if (!coinTransaction.Error) { bool sentToRabbit = await SendCompleteEvent(transaction.TransactionHash, transaction.OperationId, true, context, transaction); if (sentToRabbit) { await _log.WriteInfoAsync(nameof(HotWalletMonitoringTransactionJob), "Execute", "", $"Put coin transaction {transaction.TransactionHash} to rabbit queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } else { await _log.WriteInfoAsync(nameof(HotWalletMonitoringTransactionJob), "Execute", "", $"Put coin transaction {transaction.TransactionHash} to monitoring queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } } else { await _slackNotifier.ErrorAsync($"EthereumCoreService: HOTWALLET - Transaction with hash {transaction.TransactionHash} has an Error!"); await RepeatOperationTillWin(transaction); await _slackNotifier.ErrorAsync($"EthereumCoreService: HOTWALLET - Transaction with hash {transaction.TransactionHash} has an Error. RETRY!"); } } else { SendMessageToTheQueueEnd(context, transaction, 100); await _log.WriteInfoAsync(nameof(HotWalletMonitoringTransactionJob), "Execute", "", $"Put coin transaction {transaction.TransactionHash} to monitoring queue with confimation level {coinTransaction?.ConfirmationLevel ?? 0}"); } } }
public async Task Execute(OperationHashMatchMessage opMessage, QueueTriggeringContext context) { try { string operatioId = opMessage.OperationId; IOperationResubmitt opResubmitCounter = await _operationResubmittRepository.GetAsync(operatioId); if (opResubmitCounter == null) { opResubmitCounter = new OperationResubmitt() { OperationId = operatioId, ResubmittCount = 0 }; } if (opResubmitCounter.ResubmittCount > 2) { await _log.WriteWarningAsync("CoinEventResubmittJob", "Execute", "", $"Message put to poison {opMessage.OperationId}"); context.MoveMessageToPoison(opMessage.ToJson()); return; } var historicalMessages = await _pendingOperationService.GetHistoricalAsync(opMessage.OperationId); if (historicalMessages == null || historicalMessages.Count() == 0) { //Process cashin operations var coinEvent = await _coinEventService.GetCoinEventById(opMessage.OperationId); if (coinEvent != null && await _ethereumTransactionService.IsTransactionExecuted(coinEvent.TransactionHash, Constants.GasForCoinTransaction)) { await ResubmittTransactionAsync(coinEvent.TransactionHash, operatioId, opResubmitCounter); return; } else { context.MoveMessageToPoison(opMessage.ToJson()); await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: no corresponding coinEvent"); } } else { //Process transfer/cashout operations foreach (var match in historicalMessages) { if (!string.IsNullOrEmpty(match.TransactionHash) && await _ethereumTransactionService.IsTransactionExecuted(match.TransactionHash, Constants.GasForCoinTransaction)) { var coinEvent = await _coinEventService.GetCoinEventById(match.OperationId); if (coinEvent != null && coinEvent.TransactionHash.ToLower() == match.TransactionHash.ToLower()) { await ResubmittTransactionAsync(match.TransactionHash, operatioId, opResubmitCounter); break; } } } } } catch (Exception ex) { if (opMessage.DequeueCount > 100000) { context.MoveMessageToPoison(opMessage.ToJson()); await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: dequeue count is {opMessage.DequeueCount }" + $" error is {ex.Message}"); return; } opMessage.LastError = ex.Message; opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "", ex); return; } if (opMessage.DequeueCount > 100000) { context.MoveMessageToPoison(opMessage.ToJson()); await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: dequeue count is {opMessage.DequeueCount }"); } else { opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); } }
public async Task TransferToCoinContract(Erc20DepositContractTransaction contractTransferTr) { try { var tokenAddress = contractTransferTr.TokenAddress; var contractAddress = contractTransferTr.ContractAddress; var userAddress = contractTransferTr.UserAddress; if (string.IsNullOrEmpty(userAddress) || userAddress == Constants.EmptyEthereumAddress) { await UpdateUserTransferWallet(contractTransferTr); await _logger.WriteInfoAsync("TransferContractTransactionService", "TransferToCoinContract", "", $"Can't cashin: there is no user assigned to the transfer contract {contractTransferTr.ContractAddress}", DateTime.UtcNow); return; } if (string.IsNullOrEmpty(contractAddress) || contractAddress == Constants.EmptyEthereumAddress) { await UpdateUserTransferWallet(contractTransferTr); await _logger.WriteInfoAsync("TransferContractTransactionService", "TransferToCoinContract", "", $"Can't cashin: there is no contract address in message{contractTransferTr?.ToJson()}", DateTime.UtcNow); return; } var balance = await _ercInterfaceService.GetBalanceForExternalTokenAsync(contractAddress, contractTransferTr.TokenAddress); if (balance == 0) { await UpdateUserTransferWallet(contractTransferTr); await _logger.WriteInfoAsync("TransferContractTransactionService", "TransferToCoinContract", "", $"Can't cashin: there is no funds on the transfer contract {contractAddress}", DateTime.UtcNow); return; } var opId = $"HotWalletCashin-{Guid.NewGuid().ToString()}"; string transactionHash = null; try { transactionHash = await _hotWalletService.StartCashinAsync(new HotWalletOperation() { Amount = balance, FromAddress = contractAddress, OperationId = opId, ToAddress = _hotWalletAddress, TokenAddress = tokenAddress, OperationType = HotWalletOperationType.Cashin, }); await _cointTransactionQueue.PutRawMessageAsync(JsonConvert.SerializeObject(new CoinTransactionMessage() { TransactionHash = transactionHash })); } catch (ClientSideException clientSideExc) { var context = new { obj = contractTransferTr.ToJson(), exc = $"{clientSideExc.ExceptionType} {clientSideExc.Message} {clientSideExc.StackTrace}" }.ToJson(); await _logger.WriteInfoAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract), $"{context}"); await UpdateUserTransferWallet(contractTransferTr); //Redirect issues to dedicated slack channel await _slackNotifier.ErrorAsync($"{nameof(Erc20DepositTransactionService)} can't start cashin {context}"); return; } catch (Exception exc) { await _logger.WriteErrorAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract), $"{contractTransferTr.ToJson()}", exc); await UpdateUserTransferWallet(contractTransferTr); return; } await _userPaymentHistoryRepository.SaveAsync(new UserPaymentHistory() { Amount = balance.ToString(), ToAddress = contractAddress, AdapterAddress = $"HotWallet-Token-{tokenAddress}", CreatedDate = DateTime.UtcNow, Note = $"Cashin from erc20 deposit contract {contractAddress}", TransactionHash = transactionHash, UserAddress = contractTransferTr.UserAddress }); //await UpdateUserTransferWallet(contractTransferTr); await _logger.WriteInfoAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract), "", $"Transfered {balance} from erc 20 deposit contract to {_hotWalletAddress} by transaction {transactionHash}. " + $"Receiver = {userAddress}"); } catch (Exception e) { await _logger.WriteErrorAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract), $"{contractTransferTr.ContractAddress} - erc20 - {contractTransferTr.TokenAddress} - {contractTransferTr.Amount}", e); throw; } }