Example #1
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);
            }
        }
        public async Task BroadcastTransaction(BroadcastingTransaction transaction, QueueTriggeringContext context)
        {
            try
            {
                var signedByClientTr = await _transactionBlobStorage.GetTransaction(transaction.TransactionId, TransactionBlobType.Initial);

                var signedByExchangeTr = await _exchangeSignatureApi.SignTransaction(signedByClientTr);

                if (!await _settingsRepository.Get(Constants.CanBeBroadcastedSetting, true))
                {
                    await _transactionBlobStorage.AddOrReplaceTransaction(transaction.TransactionId, TransactionBlobType.Signed, signedByExchangeTr);

                    context.MoveMessageToPoison(transaction.ToJson());
                    return;
                }

                var tr = new Transaction(signedByExchangeTr);
                await _broadcastService.BroadcastTransaction(transaction.TransactionId, tr);

                if (transaction.TransactionCommandType == TransactionCommandType.SegwitTransferToHotwallet)
                {
                    _cqrsEngine.PublishEvent(new CashinCompletedEvent {
                        OperationId = transaction.TransactionId, TxHash = tr.GetHash().ToString()
                    }, BitcoinBoundedContext.Name);
                }

                if (transaction.TransactionCommandType == TransactionCommandType.Transfer)
                {
                    _cqrsEngine.PublishEvent(new CashoutCompletedEvent {
                        OperationId = transaction.TransactionId, TxHash = tr.GetHash().ToString()
                    }, BitcoinBoundedContext.Name);
                }
            }
            catch (RPCException e)
            {
                if (e.Message != transaction.LastError)
                {
                    await _logger.WriteWarningAsync("BroadcastingTransactionFunction", "BroadcastTransaction", $"Id: [{transaction.TransactionId}]", $"Message: {e.Message} Code:{e.RPCCode} CodeMessage:{e.RPCCodeMessage}");
                }

                transaction.LastError = e.Message;

                var unacceptableTx = _unacceptableTxErrors.Any(o => e.Message.Contains(o));

                if (transaction.DequeueCount >= _settings.MaxDequeueCount || unacceptableTx)
                {
                    context.MoveMessageToPoison();
                }
                else
                {
                    transaction.DequeueCount++;
                    context.MoveMessageToEnd(transaction.ToJson());
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
                }
            }
        }
        public async Task Execute(TransferContractTransaction contractTransferTr, QueueTriggeringContext context)
        {
            try
            {
                await _contractTransferTransactionService.TransferToCoinContract(contractTransferTr);
            }
            catch (Exception ex)
            {
                if (ex.Message != contractTransferTr.LastError)
                {
                    await _log.WriteWarningAsync("MonitoringCoinTransactionJob", "Execute", $"ContractAddress: [{contractTransferTr.ContractAddress}]", "");
                }

                contractTransferTr.LastError = ex.Message;

                if (contractTransferTr.DequeueCount >= _settings.MaxDequeueCount)
                {
                    context.MoveMessageToPoison();
                }
                else
                {
                    contractTransferTr.DequeueCount++;
                    context.MoveMessageToEnd(contractTransferTr.ToJson());
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
                }
                await _log.WriteErrorAsync("TransferTransactionQueueJob", "TransferTransactionQueue", "", ex);
            }
        }
Example #4
0
        public async Task Execute(Erc20DepositContractTransaction transaction, QueueTriggeringContext context)
        {
            try
            {
                await _transferContractTransactionService.TransferToCoinContract(transaction);
            }
            catch (Exception ex)
            {
                if (ex.Message != transaction.LastError)
                {
                    await _logger.WriteWarningAsync(nameof(Erc20DepositMonitoringCashinTransactions),
                                                    "Execute",
                                                    $"ContractAddress: [{transaction.ContractAddress}]", "");
                }

                transaction.LastError = ex.Message;

                if (transaction.DequeueCount >= 5)
                {
                    context.MoveMessageToPoison(transaction.ToJson());
                }
                else
                {
                    transaction.DequeueCount++;
                    context.MoveMessageToEnd(transaction.ToJson());
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
                }
                await _logger.WriteErrorAsync(nameof(Erc20DepositMonitoringCashinTransactions), "Execute", "", ex);
            }
        }
        public async Task Monitoring(TransactionMonitoringMessage message, QueueTriggeringContext context)
        {
            if (await _transactionService.IsTransactionExecuted(message.TxHash))
            {
                await _logger.WriteInfoAsync("TransferTransactionMonitoring", "Monitoring", message.ToJson(), "Transaction mined. Firing event.");

                if (message.Type == TransactionType.Cashin)
                {
                    var amount = BigInteger.Parse(message.Amount);

                    await _userContractRepository.DecreaseBalance(message.UserContract, amount);

                    await _issueNotifier.AddNotify(message.TxHash, message.UserContract, amount.FromBlockchainAmount(Constants.TimeCoinDecimals));

                    await _logger.WriteInfoAsync("TransferTransactionMonitoring", "Monitoring", $"{message.ToJson()}, tx: [{message.TxHash}]", "Cashin success");
                }

                if (message.Type == TransactionType.Cashout)
                {
                    await _logger.WriteInfoAsync("TransferTransactionMonitoring", "Monitoring", $"{message.ToJson()}, tx: [{message.TxHash}]", "Cashout success");
                }
            }
            else if ((DateTime.UtcNow - message.PutDateTime).TotalMinutes < _settings.TransactionExecutionTimeoutMinutes)
            {
                context.MoveMessageToEnd(message.ToJson());
                context.SetCountQueueBasedDelay(5000, 100);
            }
            else
            {
                context.MoveMessageToPoison();
                await _logger.WriteWarningAsync("TransferTransactionMonitoring", "Monitoring", message.ToJson(), "Transaction is failed");
            }
        }
        public async Task Monitor(TransactionMonitoringMessage message, QueueTriggeringContext context)
        {
            try
            {
                var response = await _qBitNinjaApiCaller.GetTransaction(message.TransactionHash);

                if (response?.Block?.Confirmations > 0)
                {
                    return;
                }
            }
            catch (QBitNinjaException ex)
            {
                if (ex.Message != message.LastError)
                {
                    await _logger.WriteWarningAsync("BroadcastMonitoringFunction", "Monitor",
                                                    $"TransactionHash: {message.TransactionHash}", $"Message: {ex.Message} StatusCode:{ex.StatusCode}");
                }
                message.LastError = ex.Message;
            }
            if (DateTime.UtcNow - message.PutDateTime > TimeSpan.FromSeconds(_settings.BroadcastMonitoringPeriodSeconds))
            {
                context.MoveMessageToPoison(message.ToJson());
            }
            else
            {
                context.MoveMessageToEnd(message.ToJson());
                context.SetCountQueueBasedDelay(10000, 100);
            }
        }
        public async Task ProcessMessage(BroadcastCommitmentMessage msg, QueueTriggeringContext context)
        {
            var asset = await _assetCache.GetItemAsync(msg.Asset);

            if (asset == null)
            {
                msg.Error = "Asset is not found";
                context.MoveMessageToPoison(msg.ToJson());
                return;
            }

            await _offchainService.BroadcastCommitment(msg.Multisig, asset, msg.UseFees);
        }
Example #8
0
        public async Task Process(PaidFeesTask task, QueueTriggeringContext context)
        {
            var tr = await _qBitNinjaApi.GetTransaction(task.TransactionHash);

            if (tr == null)
            {
                if (task.TryCount > PaidFeesTask.MaxTryCount)
                {
                    context.MoveMessageToPoison();
                    return;
                }
                task.TryCount++;
                context.MoveMessageToEnd(task.ToJson());
                context.SetCountQueueBasedDelay(10000, 100);
                return;
            }
            await _paidFeesRepository.Insert(task.TransactionHash, tr.Fees.ToDecimal(MoneyUnit.BTC), task.Date, task.Multisig, task.Asset);
        }
        public async Task Execute(TransferContractUserAssignment transaction, QueueTriggeringContext context)
        {
            try
            {
                string assignedUser = await _transferContractService.GetTransferAddressUser(transaction.CoinAdapterAddress, transaction.TransferContractAddress);

                if (string.IsNullOrEmpty(assignedUser) || assignedUser == Constants.EmptyEthereumAddress)
                {
                    await _transferContractUserAssignmentQueueService.CompleteTransfer(transaction);
                }
                else
                {
                    await _logger.WriteInfoAsync("TransferContractUserAssignmentJob", "Execute", $"{transaction.TransferContractAddress}",
                                                 $"Skipp assignment, current user {assignedUser}", DateTime.UtcNow);
                }
            }
            catch (Exception ex)
            {
                if (ex.Message != transaction.LastError)
                {
                    await _logger.WriteWarningAsync("TransferContractUserAssignmentJob", "Execute", $"TransferContractAddress: [{transaction.TransferContractAddress}]", "");
                }

                transaction.LastError = ex.Message;

                if (transaction.DequeueCount >= 4)
                {
                    context.MoveMessageToPoison();
                }
                else
                {
                    transaction.DequeueCount++;
                    context.MoveMessageToEnd();
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
                }
                await _logger.WriteErrorAsync("TransferContractUserAssignmentJob", "Execute", "", ex);
            }
        }
Example #10
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)
                {
                    opMessage.DequeueCount++;
                    context.MoveMessageToEnd(opMessage.ToJson());
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);

                    return;
                }

                var guid   = Guid.Parse(operation.OperationId);
                var amount = BigInteger.Parse(operation.Amount);

                BigInteger    resultAmount;
                string        transactionHash = null;
                CoinEventType?eventType       = null;
                BigInteger    currentBalance  = await _transferContractService.GetBalanceOnAdapter(
                    operation.CoinAdapterAddress,
                    operation.FromAddress,
                    checkInPendingBlock : true);

                switch (operation.OperationType)
                {
                case OperationTypes.Cashout:
                    eventType    = CoinEventType.CashoutStarted;
                    resultAmount = amount;
                    if (!CheckBalance(currentBalance, resultAmount))
                    {
                        break;
                    }
                    transactionHash = await _exchangeContractService.CashOut(guid,
                                                                             operation.CoinAdapterAddress,
                                                                             operation.FromAddress,
                                                                             operation.ToAddress, amount, operation.SignFrom);

                    break;

                case OperationTypes.Transfer:
                    eventType    = CoinEventType.TransferStarted;
                    resultAmount = amount;
                    if (!CheckBalance(currentBalance, resultAmount))
                    {
                        break;
                    }
                    transactionHash = await transferDelegate(guid, operation.CoinAdapterAddress,
                                                             operation.FromAddress,
                                                             operation.ToAddress, amount, operation.SignFrom);

                    break;

                case OperationTypes.TransferWithChange:
                    eventType = CoinEventType.TransferStarted;
                    BigInteger change = BigInteger.Parse(operation.Change);
                    resultAmount = amount - change;
                    if (!CheckBalance(currentBalance, resultAmount))
                    {
                        break;
                    }
                    transactionHash = await _exchangeContractService.TransferWithChange(guid, operation.CoinAdapterAddress,
                                                                                        operation.FromAddress,
                                                                                        operation.ToAddress, amount, operation.SignFrom, change, operation.SignTo);

                    break;

                default:
                    await _log.WriteWarningAsync("MonitoringOperationJob", "Execute", $"Can't find right operation type for {opMessage.OperationId}", "");

                    break;
                }

                if (transactionHash != null && eventType != null)
                {
                    await _pendingOperationService.MatchHashToOpId(transactionHash, operation.OperationId);

                    await _coinEventService.PublishEvent(new CoinEvent(operation.OperationId.ToString(), transactionHash, operation.FromAddress, operation.ToAddress, resultAmount.ToString(), eventType.Value, operation.CoinAdapterAddress));

                    await _eventTraceRepository.InsertAsync(new EventTrace()
                    {
                        Note        = $"Operation Processed. Put it in the {Constants.TransactionMonitoringQueue}. With hash {transactionHash}",
                        OperationId = operation.OperationId,
                        TraceDate   = DateTime.UtcNow
                    });

                    return;
                }
            }
            catch (ClientSideException clientSideExc) when(clientSideExc.ExceptionType == ExceptionType.OperationWithIdAlreadyExists)
            {
                await _coinEventResubmittQueue.PutRawMessageAsync(JsonConvert.SerializeObject(opMessage));

                return;
            }
            catch (RpcClientException exc)
            {
                await _log.WriteErrorAsync("MonitoringOperationJob", "Execute", "RpcException", exc);

                opMessage.LastError = exc.Message;
                opMessage.DequeueCount++;
                if (opMessage.DequeueCount < 6)
                {
                    context.MoveMessageToEnd(opMessage.ToJson());
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
                }
                else
                {
                    context.MoveMessageToPoison(opMessage.ToJson());
                }

                return;
            }
            catch (Exception ex)
            {
                if (ex.Message != opMessage.LastError)
                {
                    await _log.WriteWarningAsync("MonitoringOperationJob", "Execute", $"OperationId: [{opMessage.OperationId}]", "");
                }

                opMessage.LastError = ex.Message;
                opMessage.DequeueCount++;
                context.MoveMessageToPoison(opMessage.ToJson());

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

                return;
            }

            opMessage.DequeueCount++;
            context.MoveMessageToEnd(opMessage.ToJson());
            context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
        }
        public async Task ProcessMessage(TransactionQueueMessage message, QueueTriggeringContext context)
        {
            CreateTransactionResponse transactionResponse;

            try
            {
                var request = await _signRequestRepository.GetSignRequest(message.TransactionId);

                if (request?.Invalidated == true)
                {
                    context.MoveMessageToPoison(message.ToJson());
                    return;
                }

                switch (message.Type)
                {
                case TransactionCommandType.Issue:
                    var issue = message.Command.DeserializeJson <IssueCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetIssueTransaction(
                        OpenAssetsHelper.ParseAddress(issue.Address),
                        issue.Amount, await _assetRepository.GetAssetById(issue.Asset), message.TransactionId);

                    break;

                case TransactionCommandType.Transfer:
                    var transfer = message.Command.DeserializeJson <TransferCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetTransferTransaction(
                        OpenAssetsHelper.ParseAddress(transfer.SourceAddress),
                        OpenAssetsHelper.ParseAddress(transfer.DestinationAddress), transfer.Amount,
                        await _assetRepository.GetAssetById(transfer.Asset), message.TransactionId);

                    break;

                case TransactionCommandType.TransferAll:
                    var transferAll = message.Command.DeserializeJson <TransferAllCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetTransferAllTransaction(
                        OpenAssetsHelper.ParseAddress(transferAll.SourceAddress),
                        OpenAssetsHelper.ParseAddress(transferAll.DestinationAddress),
                        message.TransactionId);

                    break;

                case TransactionCommandType.Swap:
                    var swap = message.Command.DeserializeJson <SwapCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetSwapTransaction(
                        OpenAssetsHelper.ParseAddress(swap.MultisigCustomer1),
                        swap.Amount1,
                        await _assetRepository.GetAssetById(swap.Asset1),
                        OpenAssetsHelper.ParseAddress(swap.MultisigCustomer2),
                        swap.Amount2,
                        await _assetRepository.GetAssetById(swap.Asset2),
                        message.TransactionId);

                    break;

                case TransactionCommandType.Destroy:
                    var destroy = message.Command.DeserializeJson <DestroyCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetDestroyTransaction(
                        OpenAssetsHelper.ParseAddress(destroy.Address),
                        destroy.Amount,
                        await _assetRepository.GetAssetById(destroy.Asset),
                        message.TransactionId);

                    break;

                case TransactionCommandType.SegwitTransferToHotwallet:
                    var segwitTransfer = message.Command.DeserializeJson <SegwitTransferCommand>();
                    transactionResponse = await _lykkeTransactionBuilderService.GetTransferFromSegwitWallet(
                        OpenAssetsHelper.ParseAddress(segwitTransfer.SourceAddress), message.TransactionId);

                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            catch (BackendException e) when(e.Code == ErrorCode.NoCoinsFound)
            {
                if (message.Type == TransactionCommandType.SegwitTransferToHotwallet)
                {
                    _cqrsEngine.PublishEvent(new CashinCompletedEvent {
                        OperationId = message.TransactionId
                    }, BitcoinBoundedContext.Name);
                }
                return;
            }
            catch (BackendException e)
            {
                if (e.Text != message.LastError)
                {
                    await _logger.WriteWarningAsync("TransactionBuildFunction", "ProcessMessage", $"Id: [{message.TransactionId}], cmd: [{message.Command}]", e.Text);
                }

                message.LastError = e.Text;
                if (message.DequeueCount >= _settings.MaxDequeueCount)
                {
                    context.MoveMessageToPoison(message.ToJson());
                }
                else
                {
                    message.DequeueCount++;
                    context.MoveMessageToEnd(message.ToJson());
                    context.SetCountQueueBasedDelay(_settings.MaxQueueDelay, 200);
                }
                return;
            }

            await _transactionBlobStorage.AddOrReplaceTransaction(message.TransactionId, TransactionBlobType.Initial, transactionResponse.Transaction);


            await _queueFactory(Constants.BroadcastingQueue).PutRawMessageAsync(new BroadcastingTransaction
            {
                TransactionCommandType = message.Type,
                TransactionId          = message.TransactionId
            }.ToJson());
        }
        public async Task Execute(OperationHashMatchMessage opMessage, QueueTriggeringContext context)
        {
            try
            {
                string operatioId = opMessage.OperationId;
                IOperationResubmitt opResubmitCounter = await _operationResubmittRepository.GetAsync(operatioId);

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

                    context.MoveMessageToPoison(opMessage.ToJson());

                    return;
                }

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

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

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

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

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

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

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

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

                return;
            }

            if (opMessage.DequeueCount > 100000)
            {
                context.MoveMessageToPoison(opMessage.ToJson());
                await _slackNotifier.ErrorAsync($"Moved message {opMessage.OperationId} to poison: dequeue count is {opMessage.DequeueCount }");
            }
            else
            {
                opMessage.DequeueCount++;
                context.MoveMessageToEnd(opMessage.ToJson());
            }
        }