コード例 #1
0
        //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);
            }
        }
コード例 #2
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(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}");
                }
            }
        }
コード例 #3
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);
            }
        }
コード例 #4
0
        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);
            }
        }
コード例 #5
0
        //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);
            }
        }
コード例 #6
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}");
                }
            }
        }
コード例 #7
0
 private static void MoveToEnd(QueueTriggeringContext context, SpendCommitmentMonitorindMessage message)
 {
     context.MoveMessageToEnd(message.ToJson());
     context.SetCountQueueBasedDelay(10000, 100);
 }
コード例 #8
0
        //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);
            }
        }
コード例 #9
0
        //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);
            }
        }
コード例 #10
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}");
                }
            }
        }
コード例 #11
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());
            }
        }
コード例 #12
0
        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);
        }
コード例 #13
0
 private void MoveMessageToQueueEnd(OperationHashMatchMessage opMessage, QueueTriggeringContext context)
 {
     opMessage.DequeueCount++;
     context.MoveMessageToEnd(opMessage.ToJson());
     context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
 }
コード例 #14
0
        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());
        }
コード例 #15
0
        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);
            }
        }
コード例 #16
0
 public async Task Execute(OperationHashMatchMessage opMessage, QueueTriggeringContext context)
 {
     await ProcessOperation(opMessage, context, _exchangeContractService.Transfer);
 }
コード例 #17
0
        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);
            }
        }