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()); }
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()); }
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 })); }