public IActionResult GetTransactionFeeEstimate([FromQuery] TxFeeEstimateRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { return(BuildErrorResponse(this.ModelState)); } try { var destination = BitcoinAddress.Create(request.DestinationAddress, this.network).ScriptPubKey; var context = new TransactionBuildContext( new WalletAccountReference(request.WalletName, request.AccountName), new[] { new Recipient { Amount = request.Amount, ScriptPubKey = destination } }.ToList()) { FeeType = FeeParser.Parse(request.FeeType), MinConfirmations = request.AllowUnconfirmed ? 0 : 1, }; return(this.Json(this.walletTransactionHandler.EstimateFee(context))); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public IActionResult BuildTransaction([FromBody] BuildTransactionRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { return(ModelStateErrors.BuildErrorResponse(this.ModelState)); } try { Script destination = BitcoinAddress.Create(request.DestinationAddress, this.network).ScriptPubKey; var context = new TransactionBuildContext(this.network) { AccountReference = new WalletAccountReference(request.WalletName, request.AccountName), TransactionFee = string.IsNullOrEmpty(request.FeeAmount) ? null : Money.Parse(request.FeeAmount), MinConfirmations = request.AllowUnconfirmed ? 0 : 1, Shuffle = request.ShuffleOutputs ?? true, // We shuffle transaction outputs by default as it's better for anonymity. OpReturnData = request.OpReturnData, WalletPassword = request.Password, Recipients = new[] { new Recipient { Amount = request.Amount, ScriptPubKey = destination } }.ToList() }; context.SingleChangeAddress = request.SingleChangeAddress; if (!string.IsNullOrEmpty(request.FeeType)) { context.FeeType = FeeParser.Parse(request.FeeType); } Transaction transactionResult = this.walletTransactionHandler.BuildTransaction(context); var model = new WalletBuildTransactionModel { Hex = transactionResult.ToHex(), Fee = context.TransactionFee, TransactionId = transactionResult.GetHash() }; return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public IActionResult BuildTransaction([FromBody] BuildTransactionRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } var destination = BitcoinAddress.Create(request.DestinationAddress, this.network).ScriptPubKey; try { var context = new TransactionBuildContext( new WalletAccountReference(request.WalletName, request.AccountName), new[] { new Recipient { Amount = request.Amount, ScriptPubKey = destination } }.ToList(), request.Password) { FeeType = FeeParser.Parse(request.FeeType), MinConfirmations = request.AllowUnconfirmed ? 0 : 1, Shuffle = true }; var transactionResult = this.walletTransactionHandler.BuildTransaction(context); var model = new WalletBuildTransactionModel { Hex = transactionResult.ToHex(), Fee = context.TransactionFee, TransactionId = transactionResult.GetHash() }; return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public IActionResult GetMaximumSpendableBalance([FromQuery] WalletMaximumBalanceRequest request) { Guard.NotNull(request, nameof(request)); // Checks the request is valid. if (!this.ModelState.IsValid) { return(BuildErrorResponse(this.ModelState)); } try { var transactionResult = this.walletTransactionHandler.GetMaximumSpendableAmount(new WalletAccountReference(request.WalletName, request.AccountName), FeeParser.Parse(request.FeeType), request.AllowUnconfirmed); return(this.Json(new MaxSpendableAmountModel { MaxSpendableAmount = transactionResult.maximumSpendableAmount, Fee = transactionResult.Fee })); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public EstimateFeeResult EstimateFee(ScTxFeeEstimateRequest request) { Features.Wallet.Wallet wallet = this.walletManager.GetWallet(request.WalletName); HdAccount account = wallet.GetAccount(request.AccountName); if (account == null) { return(EstimateFeeResult.Failure(AccountNotInWalletError, $"No account with the name '{request.AccountName}' could be found.")); } HdAddress senderAddress = account.GetCombinedAddresses().FirstOrDefault(x => x.Address == request.Sender); if (senderAddress == null) { return(EstimateFeeResult.Failure(SenderNotInWalletError, $"The given address {request.Sender} was not found in the wallet.")); } if (!this.CheckBalance(senderAddress.Address)) { return(EstimateFeeResult.Failure(InsufficientBalanceError, SenderNoBalanceError)); } List <OutPoint> selectedInputs = this.SelectInputs(request.WalletName, request.Sender, request.Outpoints); if (!selectedInputs.Any()) { return(EstimateFeeResult.Failure(InvalidOutpointsError, "Invalid list of request outpoints have been passed to the method. Please ensure that the outpoints are spendable by the sender address.")); } var recipients = new List <Recipient>(); foreach (RecipientModel recipientModel in request.Recipients) { BitcoinAddress bitcoinAddress = BitcoinAddress.Create(recipientModel.DestinationAddress, this.network); // If it's a potential SC address, check if it's a contract. if (bitcoinAddress is BitcoinPubKeyAddress bitcoinPubKeyAddress) { var address = new uint160(bitcoinPubKeyAddress.Hash.ToBytes()); if (this.stateRoot.IsExist(address)) { return(EstimateFeeResult.Failure(TransferFundsToContractError, $"The recipient address {recipientModel.DestinationAddress} is a contract. Transferring funds directly to a contract is not supported.")); } } recipients.Add(new Recipient { ScriptPubKey = bitcoinAddress.ScriptPubKey, Amount = recipientModel.Amount }); } // Build context var context = new TransactionBuildContext(this.network) { AccountReference = new WalletAccountReference(request.WalletName, request.AccountName), MinConfirmations = MinConfirmationsAllChecks, Shuffle = false, OpReturnData = request.OpReturnData, OpReturnAmount = string.IsNullOrEmpty(request.OpReturnAmount) ? null : Money.Parse(request.OpReturnAmount), SelectedInputs = selectedInputs, AllowOtherInputs = false, Recipients = recipients, ChangeAddress = senderAddress, // Unique for fee estimation TransactionFee = null, FeeType = FeeParser.Parse(request.FeeType), Sign = false, }; Money fee = this.walletTransactionHandler.EstimateFee(context); return(EstimateFeeResult.Success(fee)); }
public IActionResult BuildTransaction([FromBody] BuildTransactionRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } var destination = BitcoinAddress.Create(request.DestinationAddress, this.network).ScriptPubKey; try { var transactionResult = this.walletManager.BuildTransaction(new WalletAccountReference(request.WalletName, request.AccountName), request.Password, destination, request.Amount, FeeParser.Parse(request.FeeType), request.AllowUnconfirmed ? 0 : 1); var model = new WalletBuildTransactionModel { Hex = transactionResult.hex, Fee = transactionResult.fee, TransactionId = transactionResult.transactionId }; return(this.Json(model)); } catch (Exception e) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public IActionResult GetMaximumSpendableBalance([FromQuery] WalletMaximumBalanceRequest request) { Guard.NotNull(request, nameof(request)); // Checks the request is valid. if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } try { var transactionResult = this.walletTransactionHandler.GetMaximumSpendableAmount(new WalletAccountReference(request.WalletName, request.AccountName), FeeParser.Parse(request.FeeType), request.AllowUnconfirmed); return(this.Json(new MaxSpendableAmountModel { MaxSpendableAmount = transactionResult.maximumSpendableAmount, Fee = transactionResult.Fee })); } catch (Exception e) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }