Exemple #1
0
        public async Task <IActionResult> AddAddressToBlacklist(
            BlacklistAddressRequest request)
        {
            var result = await _addressService.AddAddressToBlacklistAsync
                         (
                address : request.Address.ToLowerInvariant(),
                reason : request.BlacklistingReason
                         );

            switch (result)
            {
            case AddAddressResult.SuccessResult _:
                return(Ok());

            case AddAddressResult.HasAlreadyBeenAddedError _:
                return(Conflict());

            default:
                throw new NotSupportedException(
                          $"{nameof(_addressService.AddAddressToBlacklistAsync)} returned unsupported result.");
            }
        }
        public async Task <BuildTransactionResult> BuildTransactionAsync(
            Guid transactionId,
            string from,
            string fromContext,
            string to,
            BigInteger transferAmount,
            bool includeFee)
        {
            var transaction = await _transactionRepository.TryGetAsync(transactionId);

            if (transaction == null)
            {
                // Check address validity

                var addressValidationResult = await _addressService.ValidateAsync(to, false, false);

                if (addressValidationResult is AddressValidationResult.Error error)
                {
                    _log.Info
                    (
                        $"Failed to build transaction [{transactionId}]. Target address [{to}] is invalid. {error.Type.ToReason()}",
                        new { transactionId, from, to }
                    );

                    return(BuildTransactionResult.TargetAddressIsInvalid());
                }

                // Calculate and validate required gas amount

                var gasAmountCalculationResult = await _calculateGasAmountStrategy.ExecuteAsync
                                                 (
                    addressService : _addressService,
                    blockchainService : _blockchainService,
                    from : from,
                    to : to,
                    transferAmount : transferAmount
                                                 );

                if (gasAmountCalculationResult is GasAmountCalculationResult.ErrorResult)
                {
                    _log.Info
                    (
                        $"Failed to build transaction [{transactionId}]. Gas amount is invalid. {gasAmountCalculationResult}",
                        new { transactionId, from, to }
                    );

                    var isContract = await _blockchainService.IsContractAsync(to);

                    if (isContract)
                    {
                        await _addressService.AddAddressToBlacklistAsync
                        (
                            address : to,
                            reason : gasAmountCalculationResult.ToString()
                        );
                    }

                    return(BuildTransactionResult.GasAmountIsInvalid());
                }

                var gasAmount = (BigInteger)gasAmountCalculationResult;

                // Calculate and validate transaction amount

                var transactionAmountCalculationResult = await _calculateTransactionAmountStrategy.ExecuteAsync
                                                         (
                    blockchainService : _blockchainService,
                    from : from,
                    transferAmount : transferAmount,
                    gasAmount : gasAmount,
                    includeFee : includeFee
                                                         );

                switch (transactionAmountCalculationResult)
                {
                case TransactionAmountCalculationResult.TransactionAmountIsTooSmallResult _:
                    _log.Info
                    (
                        $"Failed to build transaction [{transactionId}]: amount is too small.",
                        new { transactionId, from, to }
                    );

                    return(BuildTransactionResult.AmountIsTooSmall());

                case TransactionAmountCalculationResult.BalanceIsNotEnoughResult _:
                    _log.Info
                    (
                        $"Failed to build transaction [{transactionId}]: balance is not enough.",
                        new { transactionId, from, to }
                    );

                    return(BuildTransactionResult.BalanceIsNotEnough());
                }

                var transactionAmount = (BigInteger)transactionAmountCalculationResult;

                // Build transaction

                var transactionData = await _buildTransactionStrategy.ExecuteAsync
                                      (
                    transactionId : transactionId,
                    from : from,
                    to : to,
                    transactionAmount : transactionAmount,
                    gasAmount : gasAmount,
                    includeFee : includeFee
                                      );

                _log.Info
                (
                    $"Transaction [{transactionId}] has been built.",
                    new { transactionId, from, to }
                );

                return(BuildTransactionResult.Success(transactionData));
            }
            else
            {
                switch (transaction.State)
                {
                case TransactionState.Built:
                    return(BuildTransactionResult.Success(transaction.Data));

                case TransactionState.InProgress:
                case TransactionState.Completed:
                case TransactionState.Failed:
                    return(BuildTransactionResult.TransactionHasBeenBroadcasted());

                case TransactionState.Deleted:
                    return(BuildTransactionResult.TransactionHasBeenDeleted());

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
        }
        public async Task <bool> CheckAndUpdateStateAsync(
            TransactionMonitoringTask task)
        {
            try
            {
                var transaction = await _transactionRepository.TryGetAsync(task.TransactionId);

                if (transaction != null)
                {
                    var transactionChanged = false;

                    // ReSharper disable once ConvertIfStatementToSwitchStatement
                    if (transaction.State == TransactionState.InProgress)
                    {
                        transactionChanged = await CheckTransactionCompletionStateAsync(transaction);
                    }

                    if (transaction.State == TransactionState.Completed || transaction.State == TransactionState.Failed)
                    {
                        transactionChanged = await CheckTransactionConfirmationStateAsync(transaction);
                    }

                    if (transaction.State == TransactionState.Failed && transaction.IsConfirmed)
                    {
                        var isContract = await _blockchainService.IsContractAsync(transaction.To);

                        if (isContract)
                        {
                            await _addressService.AddAddressToBlacklistAsync
                            (
                                address : transaction.To,
                                reason : $"Transfer to contract failed in transaction [{transaction.TransactionId}]."
                            );
                        }
                    }

                    if (transactionChanged)
                    {
                        await _transactionRepository.UpdateAsync(transaction);
                    }

                    // ReSharper disable once SwitchStatementMissingSomeCases
                    switch (transaction.State)
                    {
                    case TransactionState.Built:
                        return(true);

                    case TransactionState.InProgress:
                        return(false);

                    case TransactionState.Completed:
                    case TransactionState.Failed:
                        return(transaction.IsConfirmed);

                    case TransactionState.Deleted:
                        return(true);

                    default:
                        throw new ArgumentException($"Transaction is in unknown state [{transaction.State}].");
                    }
                }
                else
                {
                    _log.Warning($"Transaction [{task.TransactionId}] does not exist.");

                    return(true);
                }
            }
            catch (Exception e)
            {
                _log.Warning($"Failed to check and update transaction [{task.TransactionId}] state.", e);

                return(false);
            }
        }