Add separate signing flow for PSBT

This commit is contained in:
Dennis Reimann
2021-07-26 23:28:34 +02:00
committed by Andrew Camilleri
parent d9a8443081
commit cd93a5ab6b
5 changed files with 172 additions and 1 deletions

View File

@@ -130,6 +130,14 @@ namespace BTCPayServer.Controllers
}
switch (command)
{
case "export":
var viewModel = new WalletPSBTExportViewModel {SigningContext = vm.SigningContext};
viewModel.PSBT = psbt.ToBase64();
viewModel.PSBTHex = psbt.ToHex();
viewModel.CryptoCode = network.CryptoCode;
await FetchTransactionDetails(derivationSchemeSettings, viewModel, network);
return View("WalletPSBTExport", viewModel);
case "decode":
vm.Decoded = psbt.ToString();
ModelState.Remove(nameof(vm.PSBT));

View File

@@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
namespace BTCPayServer.Models.WalletViewModels
{
public class WalletPSBTExportViewModel : WalletPSBTReadyViewModel
{
public string CryptoCode { get; set; }
public string PSBTHex { get; set; }
public string PSBT { get; set; }
[Display(Name = "Upload PSBT from file")]
public IFormFile UploadedPSBTFile { get; set; }
}
}

View File

@@ -0,0 +1,80 @@
@model WalletPSBTExportViewModel
@addTagHelper *, BundlerMinifier.TagHelpers
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData.SetActivePageAndTitle(WalletsNavPages.PSBT, "PSBT Signing", Context.GetStoreData().StoreName);
}
@section PageHeadContent {
<link href="~/vendor/vue-qrcode-reader/vue-qrcode-reader.css" rel="stylesheet" asp-append-version="true"/>
}
@section PageFootContent {
<bundle name="wwwroot/bundles/camera-bundle.min.js"></bundle>
<script>
document.addEventListener("DOMContentLoaded", function () {
initQRShow("Scan the PSBT with your wallet", @Json.Serialize(Model.PSBTHex), "scan-qr-modal");
initCameraScanningApp("Scan the PSBT from your wallet", function (data){
$("textarea#ImportedPSBT").val(data);
$("#Decode").click();
}, "scanModal");
});
</script>
}
<h4 class="mb-3">@ViewData["PageTitle"]</h4>
<div class="row">
<div class="col-lg-9 col-xl-8">
@if (Model.CanCalculateBalance)
{
<p>
This transaction will change your balance:
@if (Model.Positive)
{
<span class="text-success">@Model.BalanceChange</span>
}
else
{
<span class="text-danger">@Model.BalanceChange</span>
}
</p>
<p>
Review the details and export the PSBT for your wallet.
Sign the PSBT with your wallet and import the signed version
here for finalization and broadcastimg.
</p>
}
<partial name="_PSBTInfo" model="Model" />
<h4 class="mt-5 mb-3">Export PSBT for signing</h4>
<div class="form-group">
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")">
<input type="hidden" asp-for="CryptoCode"/>
<input type="hidden" asp-for="PSBT"/>
<div class="d-flex">
<button name="command" type="submit" class="btn btn-primary" value="save-psbt">Download PSBT file</button>
<button name="command" type="button" class="btn btn-primary only-for-js ms-2" data-bs-toggle="modal" data-bs-target="#scan-qr-modal">Show QR for wallet camera</button>
</div>
</form>
</div>
<h4 class="mt-5 mb-3">Import signed PSBT</h4>
<form class="form-group" method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" enctype="multipart/form-data">
<div class="form-group">
<label for="ImportedPSBT" class="form-label">PSBT content</label>
<textarea id="ImportedPSBT" name="PSBT" class="form-control" rows="5"></textarea>
</div>
<div class="form-group">
<label asp-for="UploadedPSBTFile" class="form-label"></label>
<input asp-for="UploadedPSBTFile" type="file" class="form-control">
</div>
<div class="d-flex">
<button type="submit" name="command" value="decode" class="btn btn-primary" id="Decode">Decode PSBT</button>
<button type="button" id="scanqrcode" class="btn btn-primary only-for-js ms-2" data-bs-toggle="modal" data-bs-target="#scanModal">Scan wallet QR with camera</button>
</div>
</form>
</div>
</div>
<partial name="ShowQR"/>
<partial name="CameraScanner"/>

View File

@@ -56,7 +56,7 @@
}
<div class="list-group mt-4">
<button type="submit" name="command" value="decode" class="list-group-item list-group-item-action" id="SignWithPSBT">
<button type="submit" name="command" value="export" class="list-group-item list-group-item-action" id="SignWithPSBT">
<div class="image">
<vc:icon symbol="wallet-file"/>
</div>

View File

@@ -0,0 +1,68 @@
@model WalletPSBTReadyViewModel
<h4 class="mt-4 mb-n3">Inputs</h4>
<table class="table table-sm table-responsive-lg">
<thead class="thead-inverse">
<tr>
<th>Index</th>
<th class="text-end">Amount</th>
</tr>
</thead>
<tbody>
@foreach (var input in Model.Inputs)
{
<tr>
@if (input.Error != null)
{
<td>
@input.Index <span class="fa fa-exclamation-triangle text-danger" title="@input.Error"></span>
</td>
}
else
{
<td>@input.Index</td>
}
@if (input.Positive)
{
<td class="text-end text-success">@input.BalanceChange</td>
}
else
{
<td class="text-end text-danger">@input.BalanceChange</td>
}
</tr>
}
</tbody>
</table>
<h4 class="mt-4 mb-n3">Outputs</h4>
<table class="table table-sm table-responsive-lg">
<thead class="thead-inverse">
<tr>
<th>Destination</th>
<th class="text-end">Amount</th>
</tr>
</thead>
<tbody>
@foreach (var destination in Model.Destinations)
{
<tr>
<td>@destination.Destination</td>
@if (destination.Positive)
{
<td class="text-end text-success">@destination.Balance</td>
}
else
{
<td class="text-end text-danger">@destination.Balance</td>
}
</tr>
}
</tbody>
</table>
@if (Model.FeeRate != null)
{
<p class="text-muted text-end">Transaction fee rate: <b>@Model.FeeRate</b></p>
}