Show the inputs of the PSBT in the review screen

This commit is contained in:
nicolas.dorier 2019-05-31 00:23:23 +09:00
parent 8379b07de0
commit c877937fdf
No known key found for this signature in database
GPG key ID: 6618763EF09186FE
3 changed files with 73 additions and 46 deletions

View file

@ -195,6 +195,19 @@ namespace BTCPayServer.Controllers
vm.Positive = balanceChange >= Money.Zero; vm.Positive = balanceChange >= Money.Zero;
} }
foreach (var input in psbtObject.Inputs)
{
var inputVm = new WalletPSBTReadyViewModel.InputViewModel();
vm.Inputs.Add(inputVm);
var mine = input.HDKeysFor(derivationSchemeSettings.AccountDerivation, signingKey, signingKeyPath).Any();
var balanceChange2 = input.GetTxOut()?.Value ?? Money.Zero;
if (mine)
balanceChange2 = -balanceChange2;
inputVm.BalanceChange = ValueToString(balanceChange2, network);
inputVm.Positive = balanceChange2 >= Money.Zero;
inputVm.Index = (int)input.Index;
}
foreach (var output in psbtObject.Outputs) foreach (var output in psbtObject.Outputs)
{ {
var dest = new WalletPSBTReadyViewModel.DestinationViewModel(); var dest = new WalletPSBTReadyViewModel.DestinationViewModel();
@ -222,7 +235,12 @@ namespace BTCPayServer.Controllers
vm.FeeRate = feeRate.ToString(); vm.FeeRate = feeRate.ToString();
} }
if (!psbtObject.IsAllFinalized() && !psbtObject.TryFinalize(out var errors)) var sanityErrors = psbtObject.CheckSanity();
if (sanityErrors.Count != 0)
{
vm.SetErrors(sanityErrors);
}
else if (!psbtObject.IsAllFinalized() && !psbtObject.TryFinalize(out var errors))
{ {
vm.SetErrors(errors); vm.SetErrors(errors);
} }

View file

@ -8,16 +8,10 @@ namespace BTCPayServer.Models.WalletViewModels
{ {
public class WalletPSBTReadyViewModel public class WalletPSBTReadyViewModel
{ {
public class FinalizeError
{
public int Index { get; set; }
public string Error { get; set; }
}
public string PSBT { get; set; } public string PSBT { get; set; }
public string SigningKey { get; set; } public string SigningKey { get; set; }
public string SigningKeyPath { get; set; } public string SigningKeyPath { get; set; }
public string GlobalError { get; set; } public string GlobalError { get; set; }
public List<FinalizeError> Errors { get; set; }
public class DestinationViewModel public class DestinationViewModel
{ {
@ -26,18 +20,26 @@ namespace BTCPayServer.Models.WalletViewModels
public string Balance { get; set; } public string Balance { get; set; }
} }
public class InputViewModel
{
public int Index { get; set; }
public string Error { get; set; }
public bool Positive { get; set; }
public string BalanceChange { get; set; }
}
public bool HasErrors => Inputs.Count == 0 || Inputs.Any(i => !string.IsNullOrEmpty(i.Error));
public string BalanceChange { get; set; } public string BalanceChange { get; set; }
public bool CanCalculateBalance { get; set; } public bool CanCalculateBalance { get; set; }
public bool Positive { get; set; } public bool Positive { get; set; }
public List<DestinationViewModel> Destinations { get; set; } = new List<DestinationViewModel>(); public List<DestinationViewModel> Destinations { get; set; } = new List<DestinationViewModel>();
public List<InputViewModel> Inputs { get; set; } = new List<InputViewModel>();
public string FeeRate { get; set; } public string FeeRate { get; set; }
internal void SetErrors(IList<PSBTError> errors) internal void SetErrors(IList<PSBTError> errors)
{ {
Errors = new List<FinalizeError>();
foreach (var err in errors) foreach (var err in errors)
{ {
Errors.Add(new FinalizeError() { Index = (int)err.InputIndex, Error = err.Message }); Inputs[(int)err.InputIndex].Error = err.Message;
} }
} }
} }

View file

@ -37,6 +37,49 @@
<div class="row"> <div class="row">
<div class="col-lg-3 text-center"></div> <div class="col-lg-3 text-center"></div>
<div class="col-lg-6 text-center"> <div class="col-lg-6 text-center">
<h4 class="text-left">Inputs</h4>
<table class="table table-sm table-responsive-lg">
<thead class="thead-inverse">
<tr>
<th style="text-align:left" class="col-md-auto">
Index
</th>
<th style="text-align:right">Amount</th>
</tr>
</thead>
<tbody>
@foreach (var input in Model.Inputs)
{
<tr>
@if (input.Error != null)
{
<td style="text-align:left">@input.Index <span class="fa fa-exclamation-triangle" style="color:red;" title="@input.Error"></span></td>
}
else
{
<td style="text-align:left">@input.Index</td>
}
@if (input.Positive)
{
<td style="text-align:right; color:green;">@input.BalanceChange</td>
}
else
{
<td style="text-align:right; color:red;">@input.BalanceChange</td>
}
</tr>
}
</tbody>
</table>
</div>
<div class="col-lg-3 text-center"></div>
</div>
<div class="row">
<div class="col-lg-3 text-center"></div>
<div class="col-lg-6 text-center">
<h4 class="text-left">Outputs</h4>
<table class="table table-sm table-responsive-lg"> <table class="table table-sm table-responsive-lg">
<thead class="thead-inverse"> <thead class="thead-inverse">
<tr> <tr>
@ -76,49 +119,13 @@
<div class="col-lg-3 text-center"></div> <div class="col-lg-3 text-center"></div>
</div> </div>
} }
@if (Model.Errors != null)
{
<div class="row">
<div class="col-lg-12 text-center">
<h4>Errors</h4>
<p>
This PSBT can't be finalized for broadcast. Please review the errors.
</p>
</div>
</div>
<div class="row">
<div class="col-lg-3 text-center"></div>
<div class="col-lg-6 text-center">
<table class="table table-sm table-responsive-lg">
<thead class="thead-inverse">
<tr>
<th style="text-align:left" class="col-md-1">
Input index
</th>
<th style="text-align:right">Error</th>
</tr>
</thead>
<tbody>
@foreach (var err in Model.Errors)
{
<tr>
<td style="text-align:left">@err.Index</td>
<td style="text-align:right; color:red;"><span class="fa fa-exclamation-triangle" title="@err.Error"></span></td>
</tr>
}
</tbody>
</table>
</div>
<div class="col-lg-3 text-center"></div>
</div>
}
<div class="row"> <div class="row">
<div class="col-lg-12 text-center"> <div class="col-lg-12 text-center">
<form method="post" asp-action="WalletPSBTReady"> <form method="post" asp-action="WalletPSBTReady">
<input type="hidden" asp-for="PSBT" /> <input type="hidden" asp-for="PSBT" />
<input type="hidden" asp-for="SigningKey" /> <input type="hidden" asp-for="SigningKey" />
<input type="hidden" asp-for="SigningKeyPath" /> <input type="hidden" asp-for="SigningKeyPath" />
@if (Model.Errors == null) @if (!Model.HasErrors)
{ {
<button type="submit" class="btn btn-primary" name="command" value="broadcast">Broadcast it</button> <span> or </span> <button type="submit" class="btn btn-primary" name="command" value="broadcast">Broadcast it</button> <span> or </span>
} }