//return whether we have sent to rabbit or not private async Task <bool> SendCompleteEvent(string transactionHash, string operationId, bool success, QueueTriggeringContext context, CoinTransactionMessage transaction) { try { var operation = await GetOperationAsync(transactionHash, operationId); if (operation == null) { return(false); } (BigInteger? amount, string blockHash, ulong blockNumber)transferedInfo = (null, null, 0); string amount = operation.Amount.ToString(); switch (operation.OperationType) { case HotWalletOperationType.Cashout: break; case HotWalletOperationType.Cashin: //There will be nothing to index in failed event if (success) { transferedInfo = await _transactionEventsService.IndexCashinEventsForErc20TransactionHashAsync( transactionHash); if (transferedInfo.amount == null || transferedInfo.amount == 0) { //Not yet indexed SendMessageToTheQueueEnd(context, transaction, 10000); return(false); } amount = transferedInfo.amount.ToString(); } break; default: return(false); } EventType eventType = success ? EventType.Completed : EventType.Failed; TransferEvent @event = new TransferEvent(operation.OperationId, transactionHash, amount, operation.TokenAddress, operation.FromAddress, operation.ToAddress, transferedInfo.blockHash, transferedInfo.blockNumber, SenderType.EthereumCore, eventType, WorkflowType.Airlines, DateTime.UtcNow); await _rabbitQueuePublisher.PublshEvent(@event); return(true); } catch (Exception e) { await _log.WriteErrorAsync(nameof(AirlinesHotWalletMonitoringTransactionJob), "SendCompletedCoinEvent", $"trHash: {transactionHash}", e, DateTime.UtcNow); SendMessageToTheQueueEnd(context, transaction, 100); return(false); } }
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(LykkePayErc20TransferMessage transaction, QueueTriggeringContext context) { IHotWalletOperation operation = null; if (string.IsNullOrEmpty(transaction?.OperationId)) { await _logger.WriteWarningAsync(nameof(Erc20DepositTransferStarterJob), "Execute", "", "Empty message skipped"); return; } try { operation = await _operationsRepository.GetAsync(transaction.OperationId); if (operation == null) { await _logger.WriteWarningAsync(nameof(Erc20DepositTransferStarterJob), "Execute", transaction.ToJson(), $"No operation for id {transaction?.OperationId} message skipped"); return; } var transactionSenderAddress = _settings.Airlines.AirlinesAddress; var balance = await _ercInterfaceService.GetPendingBalanceForExternalTokenAsync(operation.FromAddress, operation.TokenAddress); if (balance < operation.Amount) { await _logger.WriteWarningAsync(nameof(Erc20DepositTransferStarterJob), "Execute", transaction.ToJson(), $"Sendig Failed Event: DepositAddress: {operation.FromAddress}, " + $"TokenAddress: {operation.TokenAddress}, " + $"DesiredAmount: {operation.Amount} " + $"CurrentBalance {balance}"); TransferEvent @event = new TransferEvent(transaction.OperationId, "", operation.Amount.ToString(), operation.TokenAddress, operation.FromAddress, operation.ToAddress, "", 0, SenderType.EthereumCore, EventType.NotEnoughFunds, WorkflowType.Airlines, DateTime.UtcNow); await _rabbitQueuePublisher.PublshEvent(@event); return; } var trHash = await Erc223SharedService.StartDepositTransferAsync(_web3, _settings.EthereumCore.Erc223DepositContract.Abi, transactionSenderAddress, operation.FromAddress, operation.TokenAddress, operation.ToAddress, operation.Amount); await _hotWalletTransactionRepository.SaveAsync(new HotWalletCashoutTransaction() { OperationId = transaction.OperationId, TransactionHash = trHash }); var message = new CoinTransactionMessage() { OperationId = transaction.OperationId, TransactionHash = trHash }; //Observe transaction await _transactionMonitoringQueue.PutRawMessageAsync(message.ToJson()); var notificationMessage = new LykkePayErc20TransferNotificationMessage() { OperationId = transaction.OperationId, TransactionHash = trHash, Balance = operation.Amount.ToString() }; await _transactionStartedNotificationQueue.PutRawMessageAsync(notificationMessage.ToJson()); } catch (ClientSideException ex) { if (operation == null) { return; } TransferEvent @event = new TransferEvent(transaction.OperationId, "", operation.Amount.ToString(), operation.TokenAddress, operation.FromAddress, operation.ToAddress, "", 0, SenderType.EthereumCore, EventType.Failed, WorkflowType.Airlines, DateTime.UtcNow); _logger.WriteWarning("Execute", operation.ToJson(), "ClientSideException", ex); await _rabbitQueuePublisher.PublshEvent(@event); } catch (Exception ex) { if (transaction == null) { return; } if (ex.Message != transaction.LastError) { _logger.WriteWarning("Execute", transaction.ToJson(), $"{transaction.OperationId}"); } transaction.LastError = ex.Message; transaction.DequeueCount++; context.MoveMessageToEnd(transaction.ToJson()); context.SetCountQueueBasedDelay(_settings.EthereumCore.MaxQueueDelay, 200); _logger.WriteError("Execute", transaction.ToJson(), ex); } }
public async Task Execute(LykkePayErc20TransferNotificationMessage message, QueueTriggeringContext context) { if (string.IsNullOrEmpty(message?.OperationId)) { await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", "", "Empty message skipped"); return; } try { var operation = await _operationsRepository.GetAsync(message.OperationId); if (operation == null) { await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", message.ToJson(), $"No operation for id {message?.OperationId} message skipped"); return; } Transaction transaction = await _web3.Eth.Transactions.GetTransactionByHash.SendRequestAsync(message.TransactionHash); if (transaction == null) { message.LastError = "Not yet indexed"; message.DequeueCount++; context.MoveMessageToEnd(message.ToJson()); context.SetCountQueueBasedDelay(_settings.EthereumCore.MaxQueueDelay, 30000); return; } TransferEvent @event = new TransferEvent(operation.OperationId, message.TransactionHash, message.Balance, operation.TokenAddress, operation.FromAddress, operation.ToAddress, transaction?.BlockHash, (ulong)transaction?.BlockNumber.Value, SenderType.EthereumCore, EventType.Started, WorkflowType.LykkePay, DateTime.UtcNow); await _rabbitQueuePublisher.PublshEvent(@event); } catch (Exception ex) { if (message == null) { return; } if (ex.Message != message.LastError) { await _logger.WriteWarningAsync(nameof(LykkePayTransferNotificationJob), "Execute", message.ToJson(), "transaction.OperationId"); } message.LastError = ex.Message; message.DequeueCount++; context.MoveMessageToEnd(message.ToJson()); context.SetCountQueueBasedDelay(_settings.EthereumCore.MaxQueueDelay, 200); await _logger.WriteErrorAsync(nameof(LykkePayTransferNotificationJob), "Execute", message.ToJson(), ex); } }
//return whether we have sent to rabbit or not private async Task <bool> SendCompletedCoinEvent(string transactionHash, string operationId, bool success, QueueTriggeringContext context, CoinTransactionMessage transaction) { try { ICoinEvent coinEvent = await GetCoinEvent(transactionHash, operationId, success); switch (coinEvent.CoinEventType) { case CoinEventType.CashinStarted: ICashinEvent cashinEvent = await _transactionEventsService.GetCashinEvent(transactionHash); if (cashinEvent == null) { await _transactionEventsService.IndexEventsForTransaction(coinEvent.ContractAddress, transactionHash); SendMessageToTheQueueEnd(context, transaction, 100); return(false); } //transferContract - userAddress await UpdateUserTransferWallet(coinEvent.FromAddress, coinEvent.ToAddress.ToLower()); coinEvent.Amount = cashinEvent.Amount; coinEvent.CoinEventType++; break; case CoinEventType.CashoutStarted: case CoinEventType.TransferStarted: //Say that Event Is completed coinEvent.CoinEventType++; break; default: break; } #region FailedCashout if (coinEvent.CoinEventType == CoinEventType.CashoutCompleted && !success) { coinEvent.CoinEventType = CoinEventType.CashoutFailed; await _coinEventService.InsertAsync(coinEvent); SendMessageToTheQueueEnd(context, transaction, 200, "Put Failed cashout in the end of the queue"); return(false); } if (coinEvent.CoinEventType == CoinEventType.CashoutFailed && !success) { var historycal = await _pendingOperationService.GetHistoricalAsync(operationId); if (historycal != null) { foreach (var match in historycal) { if (!string.IsNullOrEmpty(match.TransactionHash) && await _ethereumTransactionService.IsTransactionExecuted(match.TransactionHash, Constants.GasForCoinTransaction)) { var @event = await _coinEventService.GetCoinEvent(match.TransactionHash); if (@event != null && @event.TransactionHash.ToLower() == match.TransactionHash.ToLower()) { await _slackNotifier.ErrorAsync($"EthereumCoreService: Transaction with hash {coinEvent.TransactionHash} [{coinEvent.OperationId}]" + $" ({coinEvent.CoinEventType}). Previously was successfully transfered"); return(false); } } } } } #endregion await _coinEventService.PublishEvent(coinEvent, putInProcessingQueue : false); await _pendingTransactionsRepository.Delete(transactionHash); await _pendingOperationService.MatchHashToOpId(transactionHash, coinEvent.OperationId); return(true); } catch (Exception e) { await _log.WriteErrorAsync("MonitoringCoinTransactionJob", "SendCompletedCoinEvent", $"trHash: {transactionHash}", e, DateTime.UtcNow); SendMessageToTheQueueEnd(context, transaction, 100); return(false); } }
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}"); } } }
private static void MoveToEnd(QueueTriggeringContext context, SpendCommitmentMonitorindMessage message) { context.MoveMessageToEnd(message.ToJson()); context.SetCountQueueBasedDelay(10000, 100); }
//return whether we have sent to rabbit or not private async Task <bool> SendCompletedCoinEvent(string transactionHash, string operationId, bool success, QueueTriggeringContext context, CoinTransactionMessage transaction) { try { ICoinEvent coinEvent = await GetCoinEvent(transactionHash, operationId, success); switch (coinEvent.CoinEventType) { case CoinEventType.CashinStarted: ICashinEvent cashinEvent = await _transactionEventsService.GetCashinEvent(transactionHash); if (cashinEvent == null) { SendMessageToTheQueueEnd(context, transaction, 100); return(false); } //transferContract - userAddress await UpdateUserTransferWallet(coinEvent.FromAddress, coinEvent.ToAddress.ToLower()); coinEvent.Amount = cashinEvent.Amount; coinEvent.CoinEventType++; break; case CoinEventType.CashoutStarted: case CoinEventType.TransferStarted: //Say that Event Is completed coinEvent.CoinEventType++; break; default: break; } await _coinEventService.PublishEvent(coinEvent, putInProcessingQueue : false); await _pendingTransactionsRepository.Delete(transactionHash); await _pendingOperationService.MatchHashToOpId(transactionHash, coinEvent.OperationId); return(true); } catch (Exception e) { await _log.WriteErrorAsync("MonitoringCoinTransactionJob", "SendCompletedCoinEvent", $"trHash: {transactionHash}", e, DateTime.UtcNow); SendMessageToTheQueueEnd(context, transaction, 100); return(false); } }
//return whether we have sent to rabbit or not private async Task <bool> SendCompleteEvent(string transactionHash, string operationId, bool success, QueueTriggeringContext context, CoinTransactionMessage transaction) { try { var operation = await GetOperationAsync(transactionHash, operationId); if (operation == null) { return(false); } string amount; Lykke.Job.EthereumCore.Contracts.Enums.HotWalletEventType type; switch (operation.OperationType) { case HotWalletOperationType.Cashout: amount = operation.Amount.ToString(); type = Lykke.Job.EthereumCore.Contracts.Enums.HotWalletEventType.CashoutCompleted; break; case HotWalletOperationType.Cashin: await _hotWalletService.RemoveCashinLockAsync(operation.TokenAddress, operation.FromAddress); amount = (await _cashinEventRepository.GetAsync(transactionHash)).Amount; type = Lykke.Job.EthereumCore.Contracts.Enums.HotWalletEventType.CashinCompleted; break; default: return(false); } HotWalletEvent @event = new HotWalletEvent(operation.OperationId, transactionHash, operation.FromAddress, operation.ToAddress, amount, operation.TokenAddress, type); await _rabbitQueuePublisher.PublshEvent(@event); return(true); } catch (Exception e) { await _log.WriteErrorAsync(nameof(HotWalletMonitoringTransactionJob), "SendCompletedCoinEvent", $"trHash: {transactionHash}", e, DateTime.UtcNow); SendMessageToTheQueueEnd(context, transaction, 100); return(false); } }
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 ProcessOperation(OperationHashMatchMessage opMessage, QueueTriggeringContext context, Func <Guid, string, string, string, BigInteger, string, Task <string> > transferDelegate) { try { var operation = await _pendingOperationService.GetOperationAsync(opMessage.OperationId); if (operation == null) { await _coinEventResubmittQueue.PutRawMessageAsync(JsonConvert.SerializeObject(opMessage)); return; } if (_hotWalletAddress == operation.FromAddress.ToLower() && opMessage.DequeueCount == 0) { MoveMessageToQueueEnd(opMessage, context); return; } var guid = Guid.Parse(operation.OperationId); var amount = BigInteger.Parse(operation.Amount); BigInteger resultAmount; string transactionHash = null; CoinEventType?eventType = null; BigInteger currentBalance = await _transferContractService.GetBalanceOnAdapter( operation.CoinAdapterAddress, operation.FromAddress, checkInPendingBlock : true); switch (operation.OperationType) { case OperationTypes.Cashout: eventType = CoinEventType.CashoutStarted; resultAmount = amount; if (!CheckBalance(currentBalance, resultAmount)) { break; } transactionHash = await _exchangeContractService.CashOut(guid, operation.CoinAdapterAddress, operation.FromAddress, operation.ToAddress, amount, operation.SignFrom); break; case OperationTypes.Transfer: eventType = CoinEventType.TransferStarted; resultAmount = amount; if (!CheckBalance(currentBalance, resultAmount)) { break; } transactionHash = await transferDelegate(guid, operation.CoinAdapterAddress, operation.FromAddress, operation.ToAddress, amount, operation.SignFrom); break; case OperationTypes.TransferWithChange: eventType = CoinEventType.TransferStarted; BigInteger change = BigInteger.Parse(operation.Change); resultAmount = amount - change; if (!CheckBalance(currentBalance, resultAmount)) { break; } transactionHash = await _exchangeContractService.TransferWithChange(guid, operation.CoinAdapterAddress, operation.FromAddress, operation.ToAddress, amount, operation.SignFrom, change, operation.SignTo); break; default: await _log.WriteWarningAsync(nameof(MonitoringOperationJob), nameof(ProcessOperation), $"Can't find right operation type for {opMessage.OperationId}", ""); break; } if (transactionHash == null && _hotWalletAddress == operation.ToAddress?.ToLower() && opMessage.DequeueCount >= _veryLongDequeueCount) { //Get rid of garbage; await _log.WriteWarningAsync(nameof(MonitoringOperationJob), nameof(ProcessOperation), $"Get rid of {opMessage.OperationId} in {Constants.PendingOperationsQueue}"); context.MoveMessageToPoison(opMessage.ToJson()); return; } if (transactionHash != null && eventType != null) { await _pendingOperationService.MatchHashToOpId(transactionHash, operation.OperationId); await _coinEventService.PublishEvent(new CoinEvent(operation.OperationId.ToString(), transactionHash, operation.FromAddress, operation.ToAddress, resultAmount.ToString(), eventType.Value, operation.CoinAdapterAddress)); await _eventTraceRepository.InsertAsync(new EventTrace() { Note = $"Operation Processed. Put it in the {Constants.TransactionMonitoringQueue}. With hash {transactionHash}", OperationId = operation.OperationId, TraceDate = DateTime.UtcNow }); return; } } catch (ClientSideException clientSideExc) when(clientSideExc.ExceptionType == ExceptionType.OperationWithIdAlreadyExists) { await _coinEventResubmittQueue.PutRawMessageAsync(JsonConvert.SerializeObject(opMessage)); return; } catch (RpcResponseException exc) { await _log.WriteErrorAsync(nameof(MonitoringOperationJob), nameof(ProcessOperation), $"OperationId: [{ opMessage.OperationId}] - RpcException", exc); opMessage.LastError = exc.Message; } catch (Exception ex) { if (ex.Message != opMessage.LastError) { await _log.WriteWarningAsync(nameof(MonitoringOperationJob), nameof(ProcessOperation), $"OperationId: [{opMessage.OperationId}]", ""); } opMessage.LastError = ex.Message; await _log.WriteErrorAsync(nameof(MonitoringOperationJob), nameof(ProcessOperation), "", ex); } MoveMessageToQueueEnd(opMessage, context); }
private void MoveMessageToQueueEnd(OperationHashMatchMessage opMessage, QueueTriggeringContext context) { opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); }
public async Task ProcessMessage(TransactionQueueMessage message, QueueTriggeringContext context) { CreateTransactionResponse transactionResponse; try { var request = await _signRequestRepository.GetSignRequest(message.TransactionId); if (request?.Invalidated == true) { context.MoveMessageToPoison(message.ToJson()); return; } switch (message.Type) { case TransactionCommandType.Issue: var issue = message.Command.DeserializeJson <IssueCommand>(); transactionResponse = await _lykkeTransactionBuilderService.GetIssueTransaction( OpenAssetsHelper.ParseAddress(issue.Address), issue.Amount, await _assetRepository.GetAssetById(issue.Asset), message.TransactionId); break; case TransactionCommandType.Transfer: var transfer = message.Command.DeserializeJson <TransferCommand>(); transactionResponse = await _lykkeTransactionBuilderService.GetTransferTransaction( OpenAssetsHelper.ParseAddress(transfer.SourceAddress), OpenAssetsHelper.ParseAddress(transfer.DestinationAddress), transfer.Amount, await _assetRepository.GetAssetById(transfer.Asset), message.TransactionId); break; case TransactionCommandType.TransferAll: var transferAll = message.Command.DeserializeJson <TransferAllCommand>(); transactionResponse = await _lykkeTransactionBuilderService.GetTransferAllTransaction( OpenAssetsHelper.ParseAddress(transferAll.SourceAddress), OpenAssetsHelper.ParseAddress(transferAll.DestinationAddress), message.TransactionId); break; case TransactionCommandType.Swap: var swap = message.Command.DeserializeJson <SwapCommand>(); transactionResponse = await _lykkeTransactionBuilderService.GetSwapTransaction( OpenAssetsHelper.ParseAddress(swap.MultisigCustomer1), swap.Amount1, await _assetRepository.GetAssetById(swap.Asset1), OpenAssetsHelper.ParseAddress(swap.MultisigCustomer2), swap.Amount2, await _assetRepository.GetAssetById(swap.Asset2), message.TransactionId); break; case TransactionCommandType.Destroy: var destroy = message.Command.DeserializeJson <DestroyCommand>(); transactionResponse = await _lykkeTransactionBuilderService.GetDestroyTransaction( OpenAssetsHelper.ParseAddress(destroy.Address), destroy.Amount, await _assetRepository.GetAssetById(destroy.Asset), message.TransactionId); break; case TransactionCommandType.SegwitTransferToHotwallet: var segwitTransfer = message.Command.DeserializeJson <SegwitTransferCommand>(); transactionResponse = await _lykkeTransactionBuilderService.GetTransferFromSegwitWallet( OpenAssetsHelper.ParseAddress(segwitTransfer.SourceAddress), message.TransactionId); break; default: throw new ArgumentOutOfRangeException(); } } catch (BackendException e) when(e.Code == ErrorCode.NoCoinsFound) { if (message.Type == TransactionCommandType.SegwitTransferToHotwallet) { _cqrsEngine.PublishEvent(new CashinCompletedEvent { OperationId = message.TransactionId }, BitcoinBoundedContext.Name); } return; } catch (BackendException e) { if (e.Text != message.LastError) { await _logger.WriteWarningAsync("TransactionBuildFunction", "ProcessMessage", $"Id: [{message.TransactionId}], cmd: [{message.Command}]", e.Text); } message.LastError = e.Text; if (message.DequeueCount >= _settings.MaxDequeueCount) { context.MoveMessageToPoison(message.ToJson()); } else { message.DequeueCount++; context.MoveMessageToEnd(message.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } return; } await _transactionBlobStorage.AddOrReplaceTransaction(message.TransactionId, TransactionBlobType.Initial, transactionResponse.Transaction); await _queueFactory(Constants.BroadcastingQueue).PutRawMessageAsync(new BroadcastingTransaction { TransactionCommandType = message.Type, TransactionId = message.TransactionId }.ToJson()); }
public async Task ExecuteCashinCompleted(CoinEventCashinCompletedMessage message, QueueTriggeringContext context) { try { if (message == null || string.IsNullOrEmpty(message.TransactionHash)) { context.MoveMessageToPoison(message?.ToJson()); } var coinEvent = await _coinEventService.GetCoinEvent(message.TransactionHash); if (coinEvent == null) { return; } if (coinEvent.CoinEventType == CoinEventType.CashinStarted) { await _coinTransactionService.PutTransactionToQueue(coinEvent.TransactionHash, coinEvent.OperationId); } } catch (Exception ex) { await _log.WriteErrorAsync("MonitoringCoinTransactionJob", "Execute", "", ex); if (message.DequeueCount > 10000) { context.MoveMessageToPoison(message.ToJson()); return; } context.MoveMessageToEnd(message.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 150); } }
public async Task Execute(OperationHashMatchMessage opMessage, QueueTriggeringContext context) { await ProcessOperation(opMessage, context, _exchangeContractService.Transfer); }
public async Task Execute(LykkePayErc20TransferMessage transaction, QueueTriggeringContext context) { IHotWalletOperation operation = null; if (string.IsNullOrEmpty(transaction?.OperationId)) { await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", "", "Empty message skipped"); return; } try { operation = await _operationsRepository.GetAsync(transaction.OperationId); if (operation == null) { await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", transaction.ToJson(), $"No operation for id {transaction?.OperationId} message skipped"); return; } var transactionSenderAddress = _settings.LykkePay.LykkePayAddress; var balance = await _ercInterfaceService.GetPendingBalanceForExternalTokenAsync(operation.FromAddress, operation.TokenAddress); if (balance == 0) { await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", transaction.ToJson(), $"DepositAddress: {operation.FromAddress}, TokenAddress: {operation.TokenAddress}"); //TODO: Transaction Failed return; } var trHash = await Erc20SharedService.StartDepositTransferAsync(_web3, _settings.EthereumCore, transactionSenderAddress, operation.FromAddress, operation.TokenAddress, operation.ToAddress); await _hotWalletTransactionRepository.SaveAsync(new HotWalletCashoutTransaction() { OperationId = transaction.OperationId, TransactionHash = trHash }); var message = new CoinTransactionMessage() { OperationId = transaction.OperationId, TransactionHash = trHash }; //Observe transaction await _transactionMonitoringQueue.PutRawMessageAsync( Newtonsoft.Json.JsonConvert.SerializeObject(message)); var notificationMessage = new LykkePayErc20TransferNotificationMessage() { OperationId = transaction.OperationId, TransactionHash = trHash, Balance = balance.ToString() //At the starting moment(may change at the end of the execution) }; await _transactionStartedNotificationQueue.PutRawMessageAsync( Newtonsoft.Json.JsonConvert.SerializeObject(notificationMessage)); } catch (ClientSideException ex) { if (operation == null) { return; } TransferEvent @event = new TransferEvent(transaction.OperationId, "", operation.Amount.ToString(), operation.TokenAddress, operation.FromAddress, operation.ToAddress, "", 0, SenderType.EthereumCore, EventType.Failed, WorkflowType.LykkePay, DateTime.UtcNow); await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", operation.ToJson(), ex); await _rabbitQueuePublisher.PublshEvent(@event); } catch (Exception ex) { if (transaction == null) { return; } if (ex.Message != transaction.LastError) { await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", transaction.ToJson(), "transaction.OperationId"); } transaction.LastError = ex.Message; transaction.DequeueCount++; context.MoveMessageToEnd(transaction.ToJson()); context.SetCountQueueBasedDelay(_settings.EthereumCore.MaxQueueDelay, 200); await _logger.WriteErrorAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute", transaction.ToJson(), ex); } }