Exemple #1
0
        public async Task <IActionResult> Broadcast([Required, FromBody] BroadcastTransactionRequest request)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest());
            }

            var broadcast = await _transactionService.GetTxBroadcastAsync(request.OperationId);

            if (broadcast != null)
            {
                return(new StatusCodeResult(StatusCodes.Status409Conflict));
            }
            try
            {
                await _transactionService.BroadcastTxAsync(request.OperationId, request.SignedTransaction);
            }
            catch (BusinessException ex)
            {
                if (ex.Data.Contains("ErrorCode"))
                {
                    return(BadRequest(StellarErrorResponse.Create(ex.Message, (BlockchainErrorCode)ex.Data["ErrorCode"])));
                }
                // technical / unknown problem
                throw ex;
            }

            return(Ok());
        }
Exemple #2
0
        public IActionResult Get()
        {
            var healthViloationMessage = _healthService.GetHealthViolationMessage();

            if (healthViloationMessage != null)
            {
                return(StatusCode(
                           (int)HttpStatusCode.InternalServerError,
                           StellarErrorResponse.Create($"Service is unhealthy: {healthViloationMessage}")));
            }

            // NOTE: Feel free to extend IsAliveResponse, to display job-specific indicators
            return(Ok(new IsAliveResponse
            {
                Name = Microsoft.Extensions.PlatformAbstractions.PlatformServices.Default.Application.ApplicationName,
                Version = Microsoft.Extensions.PlatformAbstractions.PlatformServices.Default.Application.ApplicationVersion,
                Env = Program.EnvInfo,
#if DEBUG
                IsDebug = true,
#else
                IsDebug = false,
#endif
                IssueIndicators = _healthService.GetHealthIssues()
                                  .Select(i => new IsAliveResponse.IssueIndicator
                {
                    Type = i.Type,
                    Value = i.Value
                })
            }));
        }
        public async Task <IActionResult> Broadcast([Required, FromBody] BroadcastTransactionRequest request)
        {
            if (request == null || request.OperationId.Equals(Guid.Empty))
            {
                return(BadRequest(ErrorResponse.Create("Invalid parameter").AddModelError(nameof(request.OperationId), "Must be valid guid")));
            }

            var broadcast = await _transactionService.GetTxBroadcastAsync(request.OperationId);

            if (!_transactionService.CheckSignature(request.SignedTransaction))
            {
                var errorResponse = StellarErrorResponse.Create("Wrong signature", BlockchainErrorCode.BuildingShouldBeRepeated);
                return(BadRequest(errorResponse));
            }

            if (broadcast != null)
            {
                return(new StatusCodeResult(StatusCodes.Status409Conflict));
            }
            try
            {
                await _transactionService.BroadcastTxAsync(request.OperationId, request.SignedTransaction);
            }
            catch (BusinessException ex)
            {
                // technical / unknown problem
                if (string.IsNullOrWhiteSpace(ex.ErrorCode))
                {
                    throw;
                }

                var errorResponse = StellarErrorResponse.Create(ex.Message, (BlockchainErrorCode)Enum.Parse(typeof(BlockchainErrorCode), ex.ErrorCode));
                return(BadRequest(errorResponse));
            }

            return(Ok());
        }
Exemple #4
0
        public async Task <IActionResult> BuildSingle([Required, FromBody] BuildSingleTransactionRequest request)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest());
            }

            string xdrBase64;
            var    build = await _transactionService.GetTxBuildAsync(request.OperationId);

            if (build != null)
            {
                xdrBase64 = build.XdrBase64;
            }
            else
            {
                if (!_balanceService.IsAddressValid(request.FromAddress))
                {
                    return(BadRequest(ErrorResponse.Create($"{nameof(request.FromAddress)} is not a valid")));
                }

                if (!_balanceService.IsAddressValid(request.ToAddress))
                {
                    return(BadRequest(ErrorResponse.Create($"{nameof(request.ToAddress)} is not a valid")));
                }

                if (request.AssetId != Asset.Stellar.Id)
                {
                    return(BadRequest(ErrorResponse.Create($"{nameof(request.AssetId)} was not found")));
                }

                Int64 amount;
                try
                {
                    amount = Int64.Parse(request.Amount);
                }
                catch (FormatException)
                {
                    // too small (e.g. 0.1)
                    return(BadRequest(StellarErrorResponse.Create($"Amount is too small. min=1, amount={request.Amount}", BlockchainErrorCode.AmountIsTooSmall)));
                }
                var fees = await _transactionService.GetFeesAsync();

                var fromAddressBalance = await _balanceService.GetAddressBalanceAsync(request.FromAddress, fees);

                Int64 requiredBalance;
                if (request.IncludeFee)
                {
                    requiredBalance = amount;
                    amount         -= fees.BaseFee;
                }
                else
                {
                    requiredBalance = amount + fees.BaseFee;
                };

                var availableBalance = fromAddressBalance?.Balance ?? 0;
                if (requiredBalance > availableBalance)
                {
                    return(BadRequest(StellarErrorResponse.Create($"Not enough balance to create transaction. required={requiredBalance}, available={availableBalance}"
                                                                  , BlockchainErrorCode.NotEnoughtBalance)));
                }

                xdrBase64 = await _transactionService.BuildTransactionAsync(request.OperationId, fromAddressBalance, request.ToAddress, amount);
            }

            return(Ok(new BuildTransactionResponse
            {
                TransactionContext = xdrBase64
            }));
        }
        public async Task <IActionResult> BuildSingle([Required, FromBody] BuildSingleTransactionRequest request)
        {
            if (request == null || request.OperationId.Equals(Guid.Empty))
            {
                return(BadRequest(ErrorResponse.Create("Invalid parameter").AddModelError(nameof(request.OperationId), "Must be valid guid")));
            }

            string xdrBase64;
            var    broadcast = await _transactionService.GetTxBroadcastAsync(request.OperationId);

            if (broadcast != null)
            {
                return(new StatusCodeResult(StatusCodes.Status409Conflict));
            }
            var build = await _transactionService.GetTxBuildAsync(request.OperationId);

            if (build != null)
            {
                xdrBase64 = build.XdrBase64;
            }
            else
            {
                string memo = null;

                if (!_balanceService.IsAddressValid(request.FromAddress, out var fromAddressHasExtension))
                {
                    return(BadRequest(ErrorResponse.Create($"{nameof(request.FromAddress)} is not a valid")));
                }
                if (!_balanceService.IsAddressValid(request.ToAddress, out var toAddressHasExtension))
                {
                    return(BadRequest(ErrorResponse.Create($"{nameof(request.ToAddress)} is not a valid")));
                }

                if (fromAddressHasExtension)
                {
                    if (!_balanceService.IsDepositBaseAddress(request.FromAddress))
                    {
                        return(BadRequest(ErrorResponse.Create($"{nameof(request.FromAddress)} is not a valid. Public address extension allowed for deposit base address only!")));
                    }

                    if (!_balanceService.IsDepositBaseAddress(request.ToAddress) || toAddressHasExtension)
                    {
                        return(BadRequest(ErrorResponse.Create($"{nameof(request.ToAddress)} is not a valid. Only deposit base address allowed as destination, when sending from address with public address extension!")));
                    }

                    memo = _balanceService.GetPublicAddressExtension(request.FromAddress);
                }
                var toBaseAddress = _balanceService.GetBaseAddress(request.ToAddress);
                if (toAddressHasExtension)
                {
                    memo = _balanceService.GetPublicAddressExtension(request.ToAddress);
                }

                if (request.AssetId != _blockchainAssetsService.GetNativeAsset().Id)
                {
                    return(BadRequest(ErrorResponse.Create($"{nameof(request.AssetId)} was not found")));
                }

                long amount;
                try
                {
                    amount = long.Parse(request.Amount);
                }
                catch (FormatException)
                {
                    // too small (e.g. 0.1)
                    return(BadRequest(StellarErrorResponse.Create($"Amount is too small. min=1, amount={request.Amount}", BlockchainErrorCode.AmountIsTooSmall)));
                }

                var fees = new Fees();
                if (!fromAddressHasExtension)
                {
                    fees = await _transactionService.GetFeesAsync();
                }
                var fromAddressBalance = await _balanceService.GetAddressBalanceAsync(request.FromAddress, fees);

                long requiredBalance;
                if (request.IncludeFee)
                {
                    requiredBalance = amount;
                    amount         -= fees.BaseFee;
                }
                else
                {
                    requiredBalance = amount + fees.BaseFee;
                }
                var availableBalance = fromAddressBalance.Balance;
                if (requiredBalance > availableBalance)
                {
                    return(BadRequest(StellarErrorResponse.Create($"Not enough balance to create transaction. required={requiredBalance}, available={availableBalance}",
                                                                  BlockchainErrorCode.NotEnoughBalance)));
                }

                xdrBase64 = await _transactionService.BuildTransactionAsync(request.OperationId, fromAddressBalance, toBaseAddress, memo, amount);
            }

            return(Ok(new BuildTransactionResponse
            {
                TransactionContext = xdrBase64
            }));
        }