private async Task <ReturnSignResult> GetAndCheckSign(Guid id, string coinAddress, string fromAddress, string toAddress, BigInteger amount, string signFrom)
        {
            bool isRobot      = string.IsNullOrEmpty(signFrom);
            int  retryCounter = 0;
            bool isSuccess    = false;

            do
            {
                if (isRobot)
                {
                    signFrom = await GetSign(id, coinAddress, fromAddress, toAddress, amount);
                }

                try
                {
                    ThrowOnWrongSignature(id, coinAddress, fromAddress, toAddress, amount, signFrom);
                    isSuccess = true;
                }
                catch (ClientSideException exc)
                {
                    await _log.WriteErrorAsync("PendingOperationService", "GetAndCheckSign", $" OperationId {id} - Hash {signFrom}", exc, DateTime.UtcNow);

                    await _slackNotifier.ErrorAsync($"We recieved wrong signature! Sign can't be checked:  OperationId {id} - {signFrom} - {signFrom.Length}. Do something!");

                    throw;
                }
                catch (Exception e)
                {
                    await _log.WriteErrorAsync("PendingOperationService", "GetAndCheckSign", $" OperationId {id}", e, DateTime.UtcNow);

                    if (!isRobot)
                    {
                        throw;
                    }

                    retryCounter++;
                    amount++;
                    if (retryCounter > 1)
                    {
                        await _slackNotifier.ErrorAsync($"Dark Magic Happened! Sign can't be checked:  OperationId {id} - {signFrom} - {signFrom.Length}");

                        throw;
                    }

                    await _log.WriteInfoAsync("PendingOperationService", "GetAndCheckSign", $"ID:{id}, Adpater:{coinAddress}, From:{fromAddress}, To:{toAddress}, Amount:{amount}, IsRobotSignature:{isRobot}", "Retry with amount change! Amount here is more on 1 wei than original", DateTime.UtcNow);
                }
            } while (!isSuccess && (isRobot && retryCounter < 2));


            return(new ReturnSignResult()
            {
                Amount = amount,
                Sign = signFrom,
            });
        }
Esempio n. 2
0
        public async Task <string> GetContractRaw()
        {
            Action throwAction = () =>
            {
                _slackNotifier.ErrorAsync("Chronobank integration! User contract pool is empty!");
                throw new BackendException("User contract pool is empty!", ErrorCode.ContractPoolEmpty);
            };
            var message = await _queue.GetRawMessageAsync();

            if (message == null)
            {
                throwAction();
            }

            await _queue.FinishRawMessageAsync(message);

            var contract = message.AsString;

            if (string.IsNullOrWhiteSpace(contract))
            {
                throwAction();
            }

            return(contract);
        }
        public async Task UpdateUserAssignmentFail(string contractAddress, string userAddress, string coinAdapter)
        {
            var canBeRestoredInternally = !string.IsNullOrEmpty(userAddress) && userAddress != Constants.EmptyEthereumAddress;

            var userAssignmentFail = await _userAssignmentFailRepository.GetAsync(contractAddress);

            if (userAssignmentFail == null)
            {
                userAssignmentFail = new UserAssignmentFail()
                {
                    CanBeRestoredInternally = canBeRestoredInternally,
                    ContractAddress         = contractAddress,
                    NotifiedInSlack         = false,
                    FailCount = 0
                };
            }

            if (userAssignmentFail.FailCount == _attempsBeforeReassign)
            {
                if (canBeRestoredInternally)
                {
                    var message = new TransferContractUserAssignment()
                    {
                        CoinAdapterAddress      = coinAdapter,
                        TransferContractAddress = contractAddress,
                        UserAddress             = userAddress
                    };

                    await _queueUserAssignment.PutRawMessageAsync(JsonConvert.SerializeObject(message));

                    userAssignmentFail.FailCount = 0;
                }
                else
                {
                    if (userAssignmentFail.NotifiedInSlack.HasValue &&
                        !userAssignmentFail.NotifiedInSlack.Value)
                    {
                        await _slackNotifier.ErrorAsync($"TransferAddress - {contractAddress}, UserAddress - {userAddress}, " +
                                                        $"CoinAdapter Address - {coinAdapter} can't be restored internally");

                        await _userAssignmentFailRepository.SaveAsync(userAssignmentFail);
                    }

                    return;
                }
            }
            else
            {
                userAssignmentFail.FailCount++;
            }

            await _userAssignmentFailRepository.SaveAsync(userAssignmentFail);
        }
        private async Task MoveToPoisonQueue(IQueueMessage message, string newMessageVersion)
        {
            newMessageVersion = newMessageVersion ?? message.AsString;
            if (_poisonQueueReader == null)
            {
                _poisonQueueReader = _queueReaderFactory.Create(_queueName + PoisonSuffix);
            }
            await _poisonQueueReader.AddMessageAsync(newMessageVersion);

            await _queueReader.FinishMessageAsync(message);

            if (_shouldNotify)
            {
                await _slackNotifier.ErrorAsync($"Msg put to {_queueName + PoisonSuffix}, data: {newMessageVersion}");
            }
        }
Esempio n. 5
0
        public async Task <string> GetContractAddress()
        {
            var message = await _queue.GetRawMessageAsync();

            if (message != null)
            {
                await _queue.FinishRawMessageAsync(message);

                return(message.AsString);
            }
            else
            {
                await _slackNotifier.ErrorAsync("Ethereum Core Service! Erc20 deposit contract pool is empty!");

                throw new ClientSideException(ExceptionType.ContractPoolEmpty, "Erc20 deposit contract pool is empty!");
            }
        }
        private async Task CloseMultiCashout(IMultipleCashout currentMultiCashout)
        {
            await _multiCashoutRepository.CloseMultiCashout(currentMultiCashout.MultipleCashoutId);

            await _slackNotifier.ErrorAsync($"Bitcoin: can't broadcast multicashout {currentMultiCashout.MultipleCashoutId}");
        }
 public void NotifyAboutError()
 {
     _slackNotifier.ErrorAsync("Ethereum Core Service! User contract pool is empty!");
     throw new ClientSideException(ExceptionType.ContractPoolEmpty, "Transfer contract pool is empty!");
 }
Esempio n. 8
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}");
                }
            }
        }
        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}");
                }
            }
        }
Esempio n. 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}");
                }
            }
        }
        public async Task Execute(OperationHashMatchMessage opMessage, QueueTriggeringContext context)
        {
            try
            {
                string operatioId = opMessage.OperationId;
                IOperationResubmitt opResubmitCounter = await _operationResubmittRepository.GetAsync(operatioId);

                if (opResubmitCounter == null)
                {
                    opResubmitCounter = new OperationResubmitt()
                    {
                        OperationId    = operatioId,
                        ResubmittCount = 0
                    };
                }
                if (opResubmitCounter.ResubmittCount > 2)
                {
                    await _log.WriteWarningAsync("CoinEventResubmittJob", "Execute", "", $"Message put to poison {opMessage.OperationId}");

                    context.MoveMessageToPoison(opMessage.ToJson());

                    return;
                }

                var historicalMessages = await _pendingOperationService.GetHistoricalAsync(opMessage.OperationId);

                if (historicalMessages == null || historicalMessages.Count() == 0)
                {
                    //Process cashin operations
                    var coinEvent = await _coinEventService.GetCoinEventById(opMessage.OperationId);

                    if (coinEvent != null &&
                        await _ethereumTransactionService.IsTransactionExecuted(coinEvent.TransactionHash, Constants.GasForCoinTransaction))
                    {
                        await ResubmittTransactionAsync(coinEvent.TransactionHash, operatioId, opResubmitCounter);

                        return;
                    }
                    else
                    {
                        context.MoveMessageToPoison(opMessage.ToJson());
                        await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: no corresponding coinEvent");
                    }
                }
                else
                {
                    //Process transfer/cashout operations
                    foreach (var match in historicalMessages)
                    {
                        if (!string.IsNullOrEmpty(match.TransactionHash) &&
                            await _ethereumTransactionService.IsTransactionExecuted(match.TransactionHash, Constants.GasForCoinTransaction))
                        {
                            var coinEvent = await _coinEventService.GetCoinEventById(match.OperationId);

                            if (coinEvent != null && coinEvent.TransactionHash.ToLower() == match.TransactionHash.ToLower())
                            {
                                await ResubmittTransactionAsync(match.TransactionHash, operatioId, opResubmitCounter);

                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (opMessage.DequeueCount > 100000)
                {
                    context.MoveMessageToPoison(opMessage.ToJson());
                    await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: dequeue count is {opMessage.DequeueCount }" +
                                                    $" error is {ex.Message}");

                    return;
                }
                opMessage.LastError = ex.Message;
                opMessage.DequeueCount++;
                context.MoveMessageToEnd(opMessage.ToJson());

                await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "", ex);

                return;
            }

            if (opMessage.DequeueCount > 100000)
            {
                context.MoveMessageToPoison(opMessage.ToJson());
                await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: dequeue count is {opMessage.DequeueCount }");
            }
            else
            {
                opMessage.DequeueCount++;
                context.MoveMessageToEnd(opMessage.ToJson());
            }
        }
        public async Task TransferToCoinContract(Erc20DepositContractTransaction contractTransferTr)
        {
            try
            {
                var tokenAddress    = contractTransferTr.TokenAddress;
                var contractAddress = contractTransferTr.ContractAddress;
                var userAddress     = contractTransferTr.UserAddress;

                if (string.IsNullOrEmpty(userAddress) || userAddress == Constants.EmptyEthereumAddress)
                {
                    await UpdateUserTransferWallet(contractTransferTr);

                    await _logger.WriteInfoAsync("TransferContractTransactionService", "TransferToCoinContract", "",
                                                 $"Can't cashin: there is no user assigned to the transfer contract {contractTransferTr.ContractAddress}", DateTime.UtcNow);

                    return;
                }

                if (string.IsNullOrEmpty(contractAddress) || contractAddress == Constants.EmptyEthereumAddress)
                {
                    await UpdateUserTransferWallet(contractTransferTr);

                    await _logger.WriteInfoAsync("TransferContractTransactionService", "TransferToCoinContract", "",
                                                 $"Can't cashin: there is no contract address in message{contractTransferTr?.ToJson()}", DateTime.UtcNow);

                    return;
                }

                var balance = await _ercInterfaceService.GetBalanceForExternalTokenAsync(contractAddress, contractTransferTr.TokenAddress);

                if (balance == 0)
                {
                    await UpdateUserTransferWallet(contractTransferTr);

                    await _logger.WriteInfoAsync("TransferContractTransactionService", "TransferToCoinContract", "",
                                                 $"Can't cashin: there is no funds on the transfer contract {contractAddress}", DateTime.UtcNow);

                    return;
                }

                var    opId            = $"HotWalletCashin-{Guid.NewGuid().ToString()}";
                string transactionHash = null;

                try
                {
                    transactionHash = await _hotWalletService.StartCashinAsync(new HotWalletOperation()
                    {
                        Amount        = balance,
                        FromAddress   = contractAddress,
                        OperationId   = opId,
                        ToAddress     = _hotWalletAddress,
                        TokenAddress  = tokenAddress,
                        OperationType = HotWalletOperationType.Cashin,
                    });

                    await _cointTransactionQueue.PutRawMessageAsync(JsonConvert.SerializeObject(new CoinTransactionMessage()
                    {
                        TransactionHash = transactionHash
                    }));
                }
                catch (ClientSideException clientSideExc)
                {
                    var context = new
                    {
                        obj = contractTransferTr.ToJson(),
                        exc = $"{clientSideExc.ExceptionType} {clientSideExc.Message} {clientSideExc.StackTrace}"
                    }.ToJson();
                    await _logger.WriteInfoAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract),
                                                 $"{context}");
                    await UpdateUserTransferWallet(contractTransferTr);

                    //Redirect issues to dedicated slack channel
                    await _slackNotifier.ErrorAsync($"{nameof(Erc20DepositTransactionService)} can't start cashin {context}");

                    return;
                }
                catch (Exception exc)
                {
                    await _logger.WriteErrorAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract),
                                                  $"{contractTransferTr.ToJson()}", exc);
                    await UpdateUserTransferWallet(contractTransferTr);

                    return;
                }

                await _userPaymentHistoryRepository.SaveAsync(new UserPaymentHistory()
                {
                    Amount          = balance.ToString(),
                    ToAddress       = contractAddress,
                    AdapterAddress  = $"HotWallet-Token-{tokenAddress}",
                    CreatedDate     = DateTime.UtcNow,
                    Note            = $"Cashin from erc20 deposit contract {contractAddress}",
                    TransactionHash = transactionHash,
                    UserAddress     = contractTransferTr.UserAddress
                });

                //await UpdateUserTransferWallet(contractTransferTr);
                await _logger.WriteInfoAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract), "",
                                             $"Transfered {balance} from erc 20 deposit contract to {_hotWalletAddress} by transaction {transactionHash}. " +
                                             $"Receiver = {userAddress}");
            }
            catch (Exception e)
            {
                await _logger.WriteErrorAsync(nameof(Erc20DepositTransactionService), nameof(TransferToCoinContract),
                                              $"{contractTransferTr.ContractAddress} - erc20 - {contractTransferTr.TokenAddress} - {contractTransferTr.Amount}", e);

                throw;
            }
        }