Пример #1
0
        public async Task HandleAsync(string hash)
        {
            if (string.IsNullOrEmpty(hash))
            {
                _log.Warning("Hash is empty");
                return;
            }

            var statusUpdateResult = await _operationStatusUpdater.SucceedAsync(hash);

            if (statusUpdateResult.Error == OperationStatusUpdateError.OperationNotFound)
            {
                _log.Info("Operation was not found by hash in PBF. Trying to find it via call to Executor", context: hash);
                statusUpdateResult = await _operationStatusUpdater.SyncWithBlockchainAsync(hash);
            }

            if (statusUpdateResult.Error != OperationStatusUpdateError.None)
            {
                _log.Warning("Operation status was not updated to succeeded",
                             context: new { hash, error = statusUpdateResult.Error.ToString() });
                return;
            }

            var operation = await _operationsFetcher.GetByHashAsync(hash);

            if (operation == null)
            {
                _log.Info("Succeeded in BC Operation was not found by hash", context: $"hash: {hash}");
                return;
            }

            await _transactionSucceededPublisher.PublishAsync(new TransactionSucceededEvent
            {
                OperationId = operation.Id.ToString()
            });
        }
        public async Task HandleAsync(string hash)
        {
            if (string.IsNullOrEmpty(hash))
            {
                _log.Warning("Hash is empty");
                return;
            }

            var statusUpdateResult = await _operationStatusUpdater.FailAsync(hash);

            if (statusUpdateResult.Error == OperationStatusUpdateError.OperationNotFound)
            {
                _log.Info("Operation was not found by hash in PBF. Trying to find it via call to Executor", context: hash);
                statusUpdateResult = await _operationStatusUpdater.SyncWithBlockchainAsync(hash);
            }

            if (statusUpdateResult.Error != OperationStatusUpdateError.None)
            {
                _log.Warning("Operation status was not updated to failed",
                             context: new { hash, error = statusUpdateResult.Error.ToString() });
                return;
            }

            var operation = await _operationsFetcher.GetByHashAsync(hash);

            if (operation == null)
            {
                _log.Info("Failed in BC Operation was not found by hash", context: $"hash: {hash}");
                return;
            }

            await _transactionFailedPublisher.PublishAsync(new TransactionFailedEvent
            {
                OperationId = operation.Id.ToString()
            });

            switch (operation.Type)
            {
            case OperationType.TokensTransfer:
                await ProcessTransferOperationFailure(operation);

                break;

            case OperationType.WalletLinking:
                await ProcessWalletLinkingOperationFailure(operation);

                break;

            case OperationType.WalletUnlinking:
                await ProcessWalletUnlinkingOperationFailure(operation);

                break;

            case OperationType.TransferToExternal:
                await ProcessTransferToExternalFailure(operation);

                break;

            case OperationType.CustomerWalletCreation:
            case OperationType.CustomerBonusReward:
            case OperationType.GenericOperation:
            case OperationType.StakeOperation:
            case OperationType.TransferToInternal:
            case OperationType.SetTransferToPublicFee:
            case OperationType.SeizeToInternal:
                LogErrorForFailure(operation);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(operation.Type));
            }
        }
        public async Task HandleAsync(
            string sourceAddress,
            string targetAddress,
            Money18 amount,
            string transactionHash,
            DateTime observedAt)
        {
            #region Validation

            if (string.IsNullOrEmpty(sourceAddress))
            {
                _log.Warning("Source address is empty");
                return;
            }

            if (string.IsNullOrEmpty(targetAddress))
            {
                _log.Warning("Target address is empty");
                return;
            }

            if (sourceAddress.Equals(EmptyWalletAddress) || targetAddress.Equals(EmptyWalletAddress))
            {
                return;
            }

            if (amount <= 0)
            {
                _log.Warning("Amount is less or equal 0");
                return;
            }

            if (string.IsNullOrEmpty(transactionHash))
            {
                _log.Warning("Transaction hash is empty");
                return;
            }

            #endregion

            #region Find operation

            var operation = await _operationsFetcher.GetByHashAsync(transactionHash);

            if (operation == null)
            {
                var transactionState = await _executorClient.TransactionsApi.GetTransactionStateAsync(transactionHash);

                if (transactionState.Error != GetTransactionStateError.None)
                {
                    _log.Error(message: "Already processed operation was not found by hash",
                               context: new { transactionHash, sourceAddress, targetAddress });
                    return;
                }

                if (!transactionState.OperationId.HasValue)
                {
                    _log.Warning("Operation id is empty",
                                 context: new { transactionHash, sourceAddress, targetAddress });
                    return;
                }

                operation = await _operationsFetcher.GetByIdAsync(transactionState.OperationId.Value);

                if (operation == null)
                {
                    _log.Error(message: "Already processed operation was not found by id",
                               context: new
                    {
                        id = transactionState.OperationId.Value, transactionHash, sourceAddress, targetAddress
                    });
                    return;
                }
            }

            #endregion

            var tasksForBalanceUpdate = new List <Task>();

            var sourceWalletOwner = await _walletOwnersRepository.GetByWalletAddressAsync(sourceAddress);

            if (sourceWalletOwner == null)
            {
                _log.Info("Transfer with unknown source wallet owner", context: sourceAddress);
            }
            else
            {
                tasksForBalanceUpdate.Add(_balanceService.ForceBalanceUpdateAsync(sourceWalletOwner.OwnerId, operation.Type, operation.Id));
            }

            var targetWalletOwner = await _walletOwnersRepository.GetByWalletAddressAsync(targetAddress);

            if (targetWalletOwner == null)
            {
                _log.Info("Transfer with unknown target wallet owner", context: targetAddress);
            }
            else
            {
                tasksForBalanceUpdate.Add(_balanceService.ForceBalanceUpdateAsync(targetWalletOwner.OwnerId, operation.Type, operation.Id));
            }

            await Task.WhenAll(tasksForBalanceUpdate);

            var context = JsonConvert.DeserializeObject <TokensTransferContext>(operation.ContextJson);

            //If there is not customer behind one of the wallets then this is not P2P transfer
            if (sourceWalletOwner != null && targetWalletOwner != null)
            {
                await _p2PTransferPublisher.PublishAsync(new P2PTransferDetectedEvent
                {
                    TransactionHash    = transactionHash,
                    SenderCustomerId   = sourceWalletOwner.OwnerId,
                    ReceiverCustomerId = targetWalletOwner.OwnerId,
                    Amount             = amount,
                    Timestamp          = observedAt,
                    RequestId          = context.RequestId
                });
            }

            await _transferDetectedPublisher.PublishAsync(new TransferDetectedEvent
            {
                TransactionHash    = transactionHash,
                SenderCustomerId   = sourceWalletOwner?.OwnerId,
                ReceiverCustomerId = targetWalletOwner?.OwnerId,
                Amount             = amount,
                Timestamp          = observedAt,
                RequestId          = context.RequestId
            });
        }
        public async Task HandleAsync(string transactionHash, Money18 amount, string walletAddress, DateTime observedAt)
        {
            if (string.IsNullOrEmpty(transactionHash))
            {
                _log.Warning("Mint event with empty hash received");
                return;
            }

            if (amount <= 0)
            {
                _log.Warning("Invalid amount for handling MintEvent",
                             context: new { amount, hash = transactionHash });
                return;
            }

            var walletOwner = await _walletOwnersRepository.GetByWalletAddressAsync(walletAddress);

            if (walletOwner == null)
            {
                _log.Error(message: "Mint event for wallet address which does not exist", context: walletAddress);
                return;
            }

            var operation = await _operationsFetcher.GetByHashAsync(transactionHash);

            if (operation == null)
            {
                var transactionState = await _executorClient.TransactionsApi.GetTransactionStateAsync(transactionHash);

                if (transactionState.Error != GetTransactionStateError.None)
                {
                    _log.Error(message: "Already processed operation was not found by hash",
                               context: new { hash = transactionHash, walletOwner, walletAddress });
                    return;
                }

                if (!transactionState.OperationId.HasValue)
                {
                    _log.Warning("Operation id is empty", context: new { hash = transactionHash, amount, walletAddress });
                    return;
                }

                operation = await _operationsFetcher.GetByIdAsync(transactionState.OperationId.Value);

                if (operation == null)
                {
                    _log.Error(message: "Already processed operation was not found by id",
                               context: new { id = transactionState.OperationId.Value, transactionHash, walletOwner, walletAddress });
                    return;
                }
            }

            await _balanceService.ForceBalanceUpdateAsync(walletOwner.OwnerId, operation.Type, operation.Id);

            var bonusRewardContext = JsonConvert.DeserializeObject <CustomerBonusRewardContext>(operation.ContextJson);

            await _bonusRewardDetectedPublisher.PublishAsync(new BonusRewardDetectedEvent
            {
                Amount      = amount,
                Timestamp   = observedAt,
                CustomerId  = walletOwner.OwnerId,
                RequestId   = bonusRewardContext.RequestId,
                BonusReason = bonusRewardContext.BonusReason,
                CampaignId  = bonusRewardContext.CampaignId,
                ConditionId = bonusRewardContext.ConditionId
            });
        }