예제 #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);
                }

                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);
            }
        }
예제 #2
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);
            }
        }
예제 #3
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);
            }
        }
예제 #4
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 IndexCashinEventsForErc20Deposits()
        {
            var indexerStatusResponse = await _indexerApi.ApiIsAliveGetWithHttpMessagesAsync();

            if (indexerStatusResponse.Response.IsSuccessStatusCode)
            {
                var responseContent = await indexerStatusResponse.Response.Content.ReadAsStringAsync();

                var indexerStatus    = JObject.Parse(responseContent);
                var lastIndexedBlock = BigInteger.Parse(indexerStatus["blockchainTip"].Value <string>());
                var lastSyncedBlock  = await GetLastSyncedBlockNumber(HotWalletMarker);

                while (lastSyncedBlock <= lastIndexedBlock)
                {
                    //Get all transfers from block
                    var transfersResponse = await _indexerApi.ApiErc20TransferHistoryGetErc20TransfersPostAsync
                                            (
                        new GetErc20TransferHistoryRequest
                    {
                        BlockNumber = (long)lastSyncedBlock,
                    }
                                            );

                    switch (transfersResponse)
                    {
                    case IEnumerable <Erc20TransferHistoryResponse> transfers:
                        foreach (var transfer in transfers)
                        {
                            // Ignore transfers from not deposit contract addresses
                            var checkResult = await _depositContractService.ContainsWithTypeAsync(transfer.To);

                            if (!checkResult.Item1)
                            {
                                continue;
                            }

                            string trHash = transfer.TransactionHash ?? "";

                            string id =
                                (await _airHotWalletCashoutTransactionRepository.GetByTransactionHashAsync(trHash))
                                ?.OperationId ??
                                (await _lpHotWalletCashoutTransactionRepository.GetByTransactionHashAsync(trHash))
                                ?.OperationId ?? null;

                            await _rabbitQueuePublisher.PublshEvent(new TransferEvent(id,
                                                                                      transfer.TransactionHash,
                                                                                      transfer.TransferAmount,
                                                                                      transfer.Contract,
                                                                                      transfer.FromProperty,
                                                                                      transfer.To,
                                                                                      transfer.BlockHash,
                                                                                      (ulong)transfer.BlockNumber,
                                                                                      SenderType.Customer,
                                                                                      EventType.Detected,
                                                                                      (Job.EthereumCore.Contracts.Enums.LykkePay.WorkflowType)checkResult.Item2,
                                                                                      DateTime.UtcNow
                                                                                      ));
                        }

                        break;

                    case ApiException exception:
                        throw new Exception($"Ethereum indexer responded with error: {exception.Error.Message}");

                    default:
                        throw new Exception($"Ethereum indexer returned unexpected response");
                    }

                    var blockCurrent = (await _indexerApi.ApiBlockNumberByBlockNumberGetAsync((long)lastSyncedBlock)) as BlockResponse;

                    if (blockCurrent == null)
                    {
                        return;
                    }

                    var parentBlock = await _blockSyncedRepository.GetByPartitionAndHashAsync(HotWalletMarker, blockCurrent.ParentHash);

                    if (parentBlock == null)
                    {
                        lastSyncedBlock--;
                        await _blockSyncedRepository.DeleteByPartitionAndHashAsync(HotWalletMarker, blockCurrent.ParentHash);

                        continue;
                    }

                    await _blockSyncedRepository.InsertAsync(new BlockSyncedByHash()
                    {
                        BlockNumber = lastSyncedBlock.ToString(),
                        Partition   = HotWalletMarker,
                        BlockHash   = blockCurrent.BlockHash
                    });

                    lastSyncedBlock++;
                }
            }
            else
            {
                throw new Exception("Can not obtain ethereum indexer status.");
            }
        }
 public async Task PublishEvent(ICoinEvent coinEvent)
 {
     var    @event = GetCoinEvent(coinEvent);
     string coinEventSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(@event);
     await _rabbitPublisher.PublshEvent(coinEventSerialized);
 }
예제 #7
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);
            }
        }