mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Move PSBT flow into wizard
This commit is contained in:
committed by
Andrew Camilleri
parent
4371b81ef3
commit
3895b133a3
@@ -130,23 +130,22 @@ 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));
|
||||
ModelState.Remove(nameof(vm.FileName));
|
||||
ModelState.Remove(nameof(vm.UploadedPSBTFile));
|
||||
vm.PSBT = psbt.ToBase64();
|
||||
vm.PSBT = vm.SigningContext.PSBT;
|
||||
vm.PSBTHex = psbt.ToHex();
|
||||
vm.FileName = vm.UploadedPSBTFile?.FileName;
|
||||
return View(vm);
|
||||
vm.Decoded = psbt.ToString();
|
||||
await FetchTransactionDetails(derivationSchemeSettings, vm, network);
|
||||
return View("WalletPSBTDecoded", vm);
|
||||
|
||||
case "export":
|
||||
vm.PSBT = vm.SigningContext.PSBT;
|
||||
vm.PSBTHex = psbt.ToHex();
|
||||
vm.Decoded = psbt.ToString();
|
||||
await FetchTransactionDetails(derivationSchemeSettings, vm, network);
|
||||
return View("WalletPSBTExport", vm);
|
||||
|
||||
case "update":
|
||||
psbt = await ExplorerClientProvider.UpdatePSBT(derivationSchemeSettings, psbt);
|
||||
@@ -172,8 +171,10 @@ namespace BTCPayServer.Controllers
|
||||
case "combine":
|
||||
ModelState.Remove(nameof(vm.PSBT));
|
||||
return View(nameof(WalletPSBTCombine), new WalletPSBTCombineViewModel { OtherPSBT = psbt.ToBase64() });
|
||||
|
||||
case "save-psbt":
|
||||
return FilePSBT(psbt, vm.FileName);
|
||||
|
||||
default:
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Models.WalletViewModels
|
||||
{
|
||||
public class WalletPSBTViewModel
|
||||
public class WalletPSBTViewModel : WalletPSBTReadyViewModel
|
||||
{
|
||||
public string CryptoCode { get; set; }
|
||||
public string Decoded { get; set; }
|
||||
@@ -34,8 +34,6 @@ namespace BTCPayServer.Models.WalletViewModels
|
||||
[Display(Name = "Upload PSBT from file")]
|
||||
public IFormFile UploadedPSBTFile { get; set; }
|
||||
|
||||
public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
|
||||
|
||||
public async Task<PSBT> GetPSBT(Network network)
|
||||
{
|
||||
if (UploadedPSBTFile != null)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData.SetActivePageAndTitle(WalletsNavPages.PSBT, string.IsNullOrEmpty(Model.Decoded) ? "Decode PSBT" : "Decoded PSBT", Context.GetStoreData().StoreName);
|
||||
ViewData.SetActivePageAndTitle(WalletsNavPages.PSBT, "Decode PSBT", Context.GetStoreData().StoreName);
|
||||
}
|
||||
|
||||
@section PageHeadContent {
|
||||
@@ -43,34 +43,8 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.Decoded))
|
||||
{
|
||||
<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="NBXSeedAvailable"/>
|
||||
<input type="hidden" asp-for="PSBT"/>
|
||||
<input type="hidden" asp-for="FileName"/>
|
||||
<div class="d-flex">
|
||||
<button type="submit" id="SignTransaction" name="command" value="@(Model.NBXSeedAvailable ? "nbx-seed" : "sign")" class="btn btn-primary">Sign transaction</button>
|
||||
<div class="ms-2 dropdown">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="OtherActionsDropdownToggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Other actions...
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="OtherActionsDropdownToggle">
|
||||
<button name="command" type="submit" class="dropdown-item" value="broadcast">Review</button>
|
||||
<button name="command" type="submit" class="dropdown-item" value="update">Update</button>
|
||||
<button name="command" type="submit" class="dropdown-item" value="combine">Combine</button>
|
||||
<button name="command" type="submit" class="dropdown-item" value="save-psbt">Download</button>
|
||||
<button name="command" type="button" class="dropdown-item only-for-js" data-bs-toggle="modal" data-bs-target="#scan-qr-modal">Show QR</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<pre><code class="json">@Model.Decoded</code></pre>
|
||||
}
|
||||
<p>You can decode a PSBT by either pasting its content or by uploading the file.</p>
|
||||
|
||||
<p>You can decode a PSBT by either pasting its content, uploading the file or scanning the wallet QR code.</p>
|
||||
<form class="form-group" method="post" asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label asp-for="PSBT" class="form-label"></label>
|
||||
@@ -83,9 +57,10 @@
|
||||
</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>
|
||||
<button type="button" id="scanqrcode" class="btn btn-secondary 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"/>
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
@model WalletPSBTCombineViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
Layout = "_LayoutWizard";
|
||||
ViewData.SetActivePageAndTitle(WalletsNavPages.PSBT, "Combine PSBT", Context.GetStoreData().StoreName);
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<h4 class="mb-3">@ViewData["PageTitle"]</h4>
|
||||
@section Navbar {
|
||||
<a asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" onclick="history.back();return false;">
|
||||
<vc:icon symbol="back" />
|
||||
</a>
|
||||
<a asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")" class="cancel">
|
||||
<vc:icon symbol="close" />
|
||||
</a>
|
||||
}
|
||||
|
||||
<form class="form-group" method="post" asp-action="WalletPSBTCombine" enctype="multipart/form-data">
|
||||
<header class="text-center">
|
||||
<h1>@ViewData["PageTitle"]</h1>
|
||||
</header>
|
||||
|
||||
<form class="form-group" method="post" asp-action="WalletPSBTCombine" enctype="multipart/form-data">
|
||||
<input type="hidden" asp-for="OtherPSBT"/>
|
||||
<div class="form-group">
|
||||
<label asp-for="PSBT" class="form-label"></label>
|
||||
@@ -20,6 +29,4 @@
|
||||
<input type="file" class="form-control" asp-for="UploadedPSBTFile">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Combine</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
99
BTCPayServer/Views/Wallets/WalletPSBTDecoded.cshtml
Normal file
99
BTCPayServer/Views/Wallets/WalletPSBTDecoded.cshtml
Normal file
@@ -0,0 +1,99 @@
|
||||
@model WalletPSBTViewModel
|
||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||
@{
|
||||
Layout = "_LayoutWizard";
|
||||
ViewData.SetActivePageAndTitle(WalletsNavPages.PSBT, "PSBT", Context.GetStoreData().StoreName);
|
||||
}
|
||||
|
||||
@section PageHeadContent {
|
||||
<link rel="stylesheet" href="~/vendor/highlightjs/default.min.css" asp-append-version="true">
|
||||
<link href="~/vendor/vue-qrcode-reader/vue-qrcode-reader.css" rel="stylesheet" asp-append-version="true"/>
|
||||
}
|
||||
|
||||
@section PageFootContent {
|
||||
<script src="~/vendor/highlightjs/highlight.min.js" asp-append-version="true"></script>
|
||||
<bundle name="wwwroot/bundles/camera-bundle.min.js"></bundle>
|
||||
<script>
|
||||
hljs.initHighlightingOnLoad();
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
initQRShow("Scan PSBT", @Json.Serialize(Model.PSBTHex), "scan-qr-modal");
|
||||
initCameraScanningApp("Scan PSBT", function (data){
|
||||
$("textarea[name=PSBT]").val(data);
|
||||
$("#Decode").click();
|
||||
}, "scanModal");
|
||||
});
|
||||
</script>
|
||||
}
|
||||
|
||||
@section Navbar {
|
||||
<a asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" onclick="history.back();return false;">
|
||||
<vc:icon symbol="back" />
|
||||
</a>
|
||||
<a asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")" class="cancel">
|
||||
<vc:icon symbol="close" />
|
||||
</a>
|
||||
}
|
||||
|
||||
<header class="text-center">
|
||||
<h1>@ViewData["PageTitle"]</h1>
|
||||
<p class="lead text-secondary mt-3">
|
||||
You can either sign the PSBT or export and update it.
|
||||
</p>
|
||||
@if (Model.CanCalculateBalance)
|
||||
{
|
||||
<p class="lead text-secondary mt-3">
|
||||
If you broadcast this transaction, your balance will change:
|
||||
<br>
|
||||
@if (Model.Positive)
|
||||
{
|
||||
<span class="text-success">@Model.BalanceChange</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-danger">@Model.BalanceChange</span>
|
||||
}
|
||||
</p>
|
||||
}
|
||||
</header>
|
||||
|
||||
<partial name="_PSBTInfo" model="Model" />
|
||||
|
||||
<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="NBXSeedAvailable"/>
|
||||
<input type="hidden" asp-for="PSBT"/>
|
||||
<input type="hidden" asp-for="FileName"/>
|
||||
<div class="d-flex justify-content-center">
|
||||
<button type="submit" id="SignTransaction" name="command" value="@(Model.NBXSeedAvailable ? "nbx-seed" : "sign")" class="btn btn-primary me-2">Sign transaction</button>
|
||||
<button type="submit" name="command" value="update" class="btn btn-secondary me-2">Update</button>
|
||||
<button type="submit" name="command" value="combine" class="btn btn-secondary">Combine</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p class="my-5 text-center">
|
||||
<a href="#ExportOptions" data-bs-toggle="collapse" class="text-secondary">Show export options</a>
|
||||
</p>
|
||||
|
||||
<div id="ExportOptions" class="collapse">
|
||||
<h4 class="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 me-2" value="save-psbt">Download PSBT file</button>
|
||||
<button name="command" type="button" class="btn btn-primary only-for-js" 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">Raw version</h4>
|
||||
<pre><code class="json">@Model.Decoded</code></pre>
|
||||
<pre><code class="text">@Model.PSBT</code></pre>
|
||||
</div>
|
||||
|
||||
<partial name="ShowQR"/>
|
||||
<partial name="CameraScanner"/>
|
||||
@@ -1,7 +1,7 @@
|
||||
@model WalletPSBTExportViewModel
|
||||
@model WalletPSBTViewModel
|
||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
Layout = "_LayoutWizard";
|
||||
ViewData.SetActivePageAndTitle(WalletsNavPages.PSBT, "PSBT Signing", Context.GetStoreData().StoreName);
|
||||
}
|
||||
|
||||
@@ -22,14 +22,26 @@
|
||||
</script>
|
||||
}
|
||||
|
||||
<h4 class="mb-3">@ViewData["PageTitle"]</h4>
|
||||
@section Navbar {
|
||||
<a asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" onclick="history.back();return false;">
|
||||
<vc:icon symbol="back" />
|
||||
</a>
|
||||
<a asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")" class="cancel">
|
||||
<vc:icon symbol="close" />
|
||||
</a>
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-9 col-xl-8">
|
||||
<header class="text-center">
|
||||
<h1>@ViewData["PageTitle"]</h1>
|
||||
<p class="lead text-secondary mt-3">
|
||||
Export the PSBT for your wallet. Sign the PSBT with your wallet and
|
||||
import the signed version here for finalization and broadcasting.
|
||||
</p>
|
||||
@if (Model.CanCalculateBalance)
|
||||
{
|
||||
<p>
|
||||
<p class="lead text-secondary mt-3">
|
||||
This transaction will change your balance:
|
||||
<br>
|
||||
@if (Model.Positive)
|
||||
{
|
||||
<span class="text-success">@Model.BalanceChange</span>
|
||||
@@ -39,16 +51,13 @@
|
||||
<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" />
|
||||
</header>
|
||||
|
||||
<h4 class="mt-5 mb-3">Export PSBT for signing</h4>
|
||||
<div class="form-group">
|
||||
<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"/>
|
||||
@@ -57,10 +66,10 @@
|
||||
<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>
|
||||
</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">
|
||||
<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>
|
||||
@@ -73,8 +82,7 @@
|
||||
<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>
|
||||
</form>
|
||||
|
||||
<partial name="ShowQR"/>
|
||||
<partial name="CameraScanner"/>
|
||||
|
||||
@@ -1,31 +1,26 @@
|
||||
@model WalletPSBTReadyViewModel
|
||||
@{
|
||||
Layout = "../Shared/_Layout.cshtml";
|
||||
Layout = "_LayoutWizard";
|
||||
ViewData.SetActivePageAndTitle(WalletsNavPages.PSBT, "Review PSBT", Context.GetStoreData().StoreName);
|
||||
}
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12 section-heading text-center">
|
||||
<partial name="_StatusMessage" />
|
||||
|
||||
@if (Model.GlobalError != null)
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
|
||||
@section Navbar {
|
||||
<a asp-action="WalletPSBT" asp-route-walletId="@Context.GetRouteValue("walletId")" onclick="history.back();return false;">
|
||||
<vc:icon symbol="back" />
|
||||
</a>
|
||||
<a asp-action="WalletSend" asp-route-walletId="@Context.GetRouteValue("walletId")" class="cancel">
|
||||
<vc:icon symbol="close" />
|
||||
</button>
|
||||
<span>@Model.GlobalError</span><br/>
|
||||
</div>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
|
||||
<h2 class="mb-4">@ViewData["PageTitle"]</h2>
|
||||
<header class="text-center">
|
||||
<h1>@ViewData["PageTitle"]</h1>
|
||||
|
||||
@if (Model.CanCalculateBalance)
|
||||
{
|
||||
<p>
|
||||
<p class="lead text-secondary mt-3">
|
||||
If you broadcast this transaction, your balance will change:
|
||||
<br>
|
||||
@if (Model.Positive)
|
||||
{
|
||||
<span class="text-success">@Model.BalanceChange</span>
|
||||
@@ -35,24 +30,28 @@
|
||||
<span class="text-danger">@Model.BalanceChange</span>
|
||||
}
|
||||
</p>
|
||||
<p>Do you want to continue?</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>This PSBT is already finalized. We can't properly detect which input or output belongs to you.</p>
|
||||
<p class="lead text-secondary mt-3">This PSBT is already finalized. We can't properly detect which input or output belongs to you.</p>
|
||||
}
|
||||
</header>
|
||||
|
||||
<partial name="_StatusMessage" />
|
||||
|
||||
@if (Model.GlobalError != null)
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
|
||||
<vc:icon symbol="close" />
|
||||
</button>
|
||||
<span>@Model.GlobalError</span><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3"></div>
|
||||
<div class="col-lg-6">
|
||||
<partial name="_PSBTInfo" model="Model" />
|
||||
</div>
|
||||
<div class="col-lg-3"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center">
|
||||
<form method="post" asp-action="WalletPSBTReady" asp-route-walletId="@Context.GetRouteValue("walletId")">
|
||||
}
|
||||
|
||||
<partial name="_PSBTInfo" model="Model" />
|
||||
|
||||
<form method="post" asp-action="WalletPSBTReady" asp-route-walletId="@Context.GetRouteValue("walletId")" class="text-center">
|
||||
<input type="hidden" asp-for="SigningKey" />
|
||||
<input type="hidden" asp-for="SigningKeyPath" />
|
||||
<partial name="SigningContext" for="SigningContext" />
|
||||
@@ -71,9 +70,4 @@
|
||||
<span> or </span>
|
||||
}
|
||||
<button type="submit" class="btn btn-secondary" name="command" value="analyze-psbt">View PSBT</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@model WalletPSBTReadyViewModel
|
||||
|
||||
<h4 class="mt-4 mb-n3">Inputs</h4>
|
||||
<h4 class="mb-n3">Inputs</h4>
|
||||
<table class="table table-sm table-responsive-lg">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user