Example #1
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
            }));
        }