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 BroadcastTransaction(BroadcastingTransaction transaction, QueueTriggeringContext context) { try { var signedByClientTr = await _transactionBlobStorage.GetTransaction(transaction.TransactionId, TransactionBlobType.Initial); var signedByExchangeTr = await _exchangeSignatureApi.SignTransaction(signedByClientTr); if (!await _settingsRepository.Get(Constants.CanBeBroadcastedSetting, true)) { await _transactionBlobStorage.AddOrReplaceTransaction(transaction.TransactionId, TransactionBlobType.Signed, signedByExchangeTr); context.MoveMessageToPoison(transaction.ToJson()); return; } var tr = new Transaction(signedByExchangeTr); await _broadcastService.BroadcastTransaction(transaction.TransactionId, tr); if (transaction.TransactionCommandType == TransactionCommandType.SegwitTransferToHotwallet) { _cqrsEngine.PublishEvent(new CashinCompletedEvent { OperationId = transaction.TransactionId, TxHash = tr.GetHash().ToString() }, BitcoinBoundedContext.Name); } if (transaction.TransactionCommandType == TransactionCommandType.Transfer) { _cqrsEngine.PublishEvent(new CashoutCompletedEvent { OperationId = transaction.TransactionId, TxHash = tr.GetHash().ToString() }, BitcoinBoundedContext.Name); } } catch (RPCException e) { if (e.Message != transaction.LastError) { await _logger.WriteWarningAsync("BroadcastingTransactionFunction", "BroadcastTransaction", $"Id: [{transaction.TransactionId}]", $"Message: {e.Message} Code:{e.RPCCode} CodeMessage:{e.RPCCodeMessage}"); } transaction.LastError = e.Message; var unacceptableTx = _unacceptableTxErrors.Any(o => e.Message.Contains(o)); if (transaction.DequeueCount >= _settings.MaxDequeueCount || unacceptableTx) { context.MoveMessageToPoison(); } else { transaction.DequeueCount++; context.MoveMessageToEnd(transaction.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } } }
public async Task Execute(TransferContractTransaction contractTransferTr, QueueTriggeringContext context) { try { await _contractTransferTransactionService.TransferToCoinContract(contractTransferTr); } catch (Exception ex) { if (ex.Message != contractTransferTr.LastError) { await _log.WriteWarningAsync("MonitoringCoinTransactionJob", "Execute", $"ContractAddress: [{contractTransferTr.ContractAddress}]", ""); } contractTransferTr.LastError = ex.Message; if (contractTransferTr.DequeueCount >= _settings.MaxDequeueCount) { context.MoveMessageToPoison(); } else { contractTransferTr.DequeueCount++; context.MoveMessageToEnd(contractTransferTr.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } await _log.WriteErrorAsync("TransferTransactionQueueJob", "TransferTransactionQueue", "", ex); } }
public async Task Execute(Erc20DepositContractTransaction transaction, QueueTriggeringContext context) { try { await _transferContractTransactionService.TransferToCoinContract(transaction); } catch (Exception ex) { if (ex.Message != transaction.LastError) { await _logger.WriteWarningAsync(nameof(Erc20DepositMonitoringCashinTransactions), "Execute", $"ContractAddress: [{transaction.ContractAddress}]", ""); } transaction.LastError = ex.Message; if (transaction.DequeueCount >= 5) { context.MoveMessageToPoison(transaction.ToJson()); } else { transaction.DequeueCount++; context.MoveMessageToEnd(transaction.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } await _logger.WriteErrorAsync(nameof(Erc20DepositMonitoringCashinTransactions), "Execute", "", ex); } }
public async Task Monitoring(TransactionMonitoringMessage message, QueueTriggeringContext context) { if (await _transactionService.IsTransactionExecuted(message.TxHash)) { await _logger.WriteInfoAsync("TransferTransactionMonitoring", "Monitoring", message.ToJson(), "Transaction mined. Firing event."); if (message.Type == TransactionType.Cashin) { var amount = BigInteger.Parse(message.Amount); await _userContractRepository.DecreaseBalance(message.UserContract, amount); await _issueNotifier.AddNotify(message.TxHash, message.UserContract, amount.FromBlockchainAmount(Constants.TimeCoinDecimals)); await _logger.WriteInfoAsync("TransferTransactionMonitoring", "Monitoring", $"{message.ToJson()}, tx: [{message.TxHash}]", "Cashin success"); } if (message.Type == TransactionType.Cashout) { await _logger.WriteInfoAsync("TransferTransactionMonitoring", "Monitoring", $"{message.ToJson()}, tx: [{message.TxHash}]", "Cashout success"); } } else if ((DateTime.UtcNow - message.PutDateTime).TotalMinutes < _settings.TransactionExecutionTimeoutMinutes) { context.MoveMessageToEnd(message.ToJson()); context.SetCountQueueBasedDelay(5000, 100); } else { context.MoveMessageToPoison(); await _logger.WriteWarningAsync("TransferTransactionMonitoring", "Monitoring", message.ToJson(), "Transaction is failed"); } }
public async Task Monitor(TransactionMonitoringMessage message, QueueTriggeringContext context) { try { var response = await _qBitNinjaApiCaller.GetTransaction(message.TransactionHash); if (response?.Block?.Confirmations > 0) { return; } } catch (QBitNinjaException ex) { if (ex.Message != message.LastError) { await _logger.WriteWarningAsync("BroadcastMonitoringFunction", "Monitor", $"TransactionHash: {message.TransactionHash}", $"Message: {ex.Message} StatusCode:{ex.StatusCode}"); } message.LastError = ex.Message; } if (DateTime.UtcNow - message.PutDateTime > TimeSpan.FromSeconds(_settings.BroadcastMonitoringPeriodSeconds)) { context.MoveMessageToPoison(message.ToJson()); } else { context.MoveMessageToEnd(message.ToJson()); context.SetCountQueueBasedDelay(10000, 100); } }
public async Task ProcessMessage(BroadcastCommitmentMessage msg, QueueTriggeringContext context) { var asset = await _assetCache.GetItemAsync(msg.Asset); if (asset == null) { msg.Error = "Asset is not found"; context.MoveMessageToPoison(msg.ToJson()); return; } await _offchainService.BroadcastCommitment(msg.Multisig, asset, msg.UseFees); }
public async Task Process(PaidFeesTask task, QueueTriggeringContext context) { var tr = await _qBitNinjaApi.GetTransaction(task.TransactionHash); if (tr == null) { if (task.TryCount > PaidFeesTask.MaxTryCount) { context.MoveMessageToPoison(); return; } task.TryCount++; context.MoveMessageToEnd(task.ToJson()); context.SetCountQueueBasedDelay(10000, 100); return; } await _paidFeesRepository.Insert(task.TransactionHash, tr.Fees.ToDecimal(MoneyUnit.BTC), task.Date, task.Multisig, task.Asset); }
public async Task Execute(TransferContractUserAssignment transaction, QueueTriggeringContext context) { try { string assignedUser = await _transferContractService.GetTransferAddressUser(transaction.CoinAdapterAddress, transaction.TransferContractAddress); if (string.IsNullOrEmpty(assignedUser) || assignedUser == Constants.EmptyEthereumAddress) { await _transferContractUserAssignmentQueueService.CompleteTransfer(transaction); } else { await _logger.WriteInfoAsync("TransferContractUserAssignmentJob", "Execute", $"{transaction.TransferContractAddress}", $"Skipp assignment, current user {assignedUser}", DateTime.UtcNow); } } catch (Exception ex) { if (ex.Message != transaction.LastError) { await _logger.WriteWarningAsync("TransferContractUserAssignmentJob", "Execute", $"TransferContractAddress: [{transaction.TransferContractAddress}]", ""); } transaction.LastError = ex.Message; if (transaction.DequeueCount >= 4) { context.MoveMessageToPoison(); } else { transaction.DequeueCount++; context.MoveMessageToEnd(); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } await _logger.WriteErrorAsync("TransferContractUserAssignmentJob", "Execute", "", ex); } }
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) { opMessage.DequeueCount++; context.MoveMessageToEnd(opMessage.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); 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("MonitoringOperationJob", "Execute", $"Can't find right operation type for {opMessage.OperationId}", ""); break; } 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 (RpcClientException exc) { await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "RpcException", exc); opMessage.LastError = exc.Message; opMessage.DequeueCount++; if (opMessage.DequeueCount < 6) { context.MoveMessageToEnd(opMessage.ToJson()); context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200); } else { context.MoveMessageToPoison(opMessage.ToJson()); } return; } catch (Exception ex) { if (ex.Message != opMessage.LastError) { await _log.WriteWarningAsync("MonitoringOperationJob", "Execute", $"OperationId: [{opMessage.OperationId}]", ""); } opMessage.LastError = ex.Message; opMessage.DequeueCount++; context.MoveMessageToPoison(opMessage.ToJson()); await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "", ex); return; } 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 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()); } }