From 3c0292f0748fe059276771d2da9fa7006079703c Mon Sep 17 00:00:00 2001 From: d11n Date: Mon, 14 Jun 2021 07:06:56 +0200 Subject: [PATCH] Wallet: Signing UI improvements (#2559) * Refactoring to generalize wizard layout * Wallet: Add intermediate signing options view * Update BTCPayServer/Views/Wallets/WalletSigningOptions.cshtml Co-authored-by: britttttk <39231115+britttttk@users.noreply.github.com> * Skip signing options for hot wallets * Update signing options wordings, add PSBT doc link * Fix test * Remove form route params * Use decode command for PSBT Co-authored-by: britttttk <39231115+britttttk@users.noreply.github.com> --- BTCPayServer.Tests/PSBTTests.cs | 12 +-- BTCPayServer.Tests/PayJoinTests.cs | 6 +- BTCPayServer.Tests/SeleniumTester.cs | 4 +- BTCPayServer.Tests/SeleniumTests.cs | 45 +++------ .../Controllers/WalletsController.PSBT.cs | 37 ++++---- BTCPayServer/Controllers/WalletsController.cs | 39 ++++---- .../WalletViewModels/SigningContextModel.cs | 1 + .../WalletViewModels/WalletPSBTViewModel.cs | 6 ++ .../WalletSigningOptionsModel.cs | 18 ++++ .../Views/Shared/_LayoutWizard.cshtml | 26 ++++++ .../Views/Stores/GenerateWalletOptions.cshtml | 6 +- .../Views/Stores/ImportWalletOptions.cshtml | 14 +-- BTCPayServer/Views/Stores/SetupWallet.cshtml | 4 +- .../Views/Stores/_LayoutWalletSetup.cshtml | 15 +-- BTCPayServer/Views/Wallets/WalletPSBT.cshtml | 8 +- BTCPayServer/Views/Wallets/WalletSend.cshtml | 8 +- .../Views/Wallets/WalletSigningMenu.cshtml | 20 ---- .../Views/Wallets/WalletSigningOptions.cshtml | 93 +++++++++++++++++++ .../main/{wallet-setup.css => wizard.css} | 22 ++--- 19 files changed, 244 insertions(+), 140 deletions(-) create mode 100644 BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs create mode 100644 BTCPayServer/Views/Shared/_LayoutWizard.cshtml delete mode 100644 BTCPayServer/Views/Wallets/WalletSigningMenu.cshtml create mode 100644 BTCPayServer/Views/Wallets/WalletSigningOptions.cshtml rename BTCPayServer/wwwroot/main/{wallet-setup.css => wizard.css} (79%) diff --git a/BTCPayServer.Tests/PSBTTests.cs b/BTCPayServer.Tests/PSBTTests.cs index 83d3e0741..2c6f7fc4e 100644 --- a/BTCPayServer.Tests/PSBTTests.cs +++ b/BTCPayServer.Tests/PSBTTests.cs @@ -86,9 +86,9 @@ namespace BTCPayServer.Tests var signedPSBT = unsignedPSBT.Clone(); signedPSBT.SignAll(user.DerivationScheme, user.GenerateWalletResponseV.AccountHDKey, user.GenerateWalletResponseV.AccountKeyPath); vmPSBT.PSBT = signedPSBT.ToBase64(); - var psbtReady = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel() + var psbtReady = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel { - SigningContext = new SigningContextModel() + SigningContext = new SigningContextModel { PSBT = AssertRedirectedPSBT(await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady)) } @@ -96,9 +96,7 @@ namespace BTCPayServer.Tests Assert.Equal(2 + 1, psbtReady.Destinations.Count); // The fee is a destination Assert.Contains(psbtReady.Destinations, d => d.Destination == sendDestination && !d.Positive); Assert.Contains(psbtReady.Destinations, d => d.Positive); - var redirect = Assert.IsType(await walletController.WalletPSBTReady(walletId, psbtReady, command: "broadcast")); - Assert.Equal(nameof(walletController.WalletTransactions), redirect.ActionName); - + vmPSBT.PSBT = unsignedPSBT.ToBase64(); var combineVM = await walletController.WalletPSBT(walletId, vmPSBT, "combine").AssertViewModelAsync(); Assert.Equal(vmPSBT.PSBT, combineVM.OtherPSBT); @@ -119,14 +117,14 @@ namespace BTCPayServer.Tests Assert.True(signedPSBT2.TryFinalize(out _)); Assert.Equal(signedPSBT, signedPSBT2); - var ready = (await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel() + var ready = (await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel { SigningContext = new SigningContextModel(signedPSBT) })).AssertViewModel(); Assert.Equal(signedPSBT.ToBase64(), ready.SigningContext.PSBT); psbt = AssertRedirectedPSBT(await walletController.WalletPSBTReady(walletId, ready, command: "analyze-psbt"), nameof(walletController.WalletPSBT)); Assert.Equal(signedPSBT.ToBase64(), psbt); - redirect = Assert.IsType(await walletController.WalletPSBTReady(walletId, ready, command: "broadcast")); + var redirect = Assert.IsType(await walletController.WalletPSBTReady(walletId, ready, command: "broadcast")); Assert.Equal(nameof(walletController.WalletTransactions), redirect.ActionName); //test base64 psbt file diff --git a/BTCPayServer.Tests/PayJoinTests.cs b/BTCPayServer.Tests/PayJoinTests.cs index 61b7aa472..99dc61448 100644 --- a/BTCPayServer.Tests/PayJoinTests.cs +++ b/BTCPayServer.Tests/PayJoinTests.cs @@ -271,8 +271,7 @@ namespace BTCPayServer.Tests s.Driver.SwitchTo().Alert().Accept(); Assert.False(string.IsNullOrEmpty(s.Driver.FindElement(By.Id("PayJoinBIP21")) .GetAttribute("value"))); - s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); - s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); + s.Driver.FindElement(By.Id("SignTransaction")).Click(); await s.Server.WaitForEvent(() => { s.Driver.FindElement(By.CssSelector("button[value=payjoin]")).Click(); @@ -307,8 +306,7 @@ namespace BTCPayServer.Tests .GetAttribute("value"))); s.Driver.FindElement(By.Id("FeeSatoshiPerByte")).Clear(); s.Driver.FindElement(By.Id("FeeSatoshiPerByte")).SendKeys("2"); - s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); - s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); + s.Driver.FindElement(By.Id("SignTransaction")).Click(); var txId = await s.Server.WaitForEvent(() => { s.Driver.FindElement(By.CssSelector("button[value=payjoin]")).Click(); diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index 44e4e9590..07ec0762d 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -363,8 +363,8 @@ namespace BTCPayServer.Tests Driver.FindElement(By.Id("bip21parse")).Click(); Driver.SwitchTo().Alert().SendKeys(bip21); Driver.SwitchTo().Alert().Accept(); - Driver.FindElement(By.Id("SendDropdownToggle")).Click(); - Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); + Driver.FindElement(By.Id("SignTransaction")).Click(); + Driver.FindElement(By.Id("SignWithSeed")).Click(); Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); } diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 14dab0213..d7caa0036 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -621,8 +621,7 @@ namespace BTCPayServer.Tests var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); SetTransactionOutput(s, 0, bob, 0.3m); - s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); - s.Driver.FindElement(By.Id("spendWithNBxplorer")).Click(); + s.Driver.FindElement(By.Id("SignTransaction")).Click(); s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); var happyElement = s.FindAlertMessage(); var happyText = happyElement.Text; @@ -768,7 +767,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("Wallets")).Click(); s.Driver.FindElement(By.LinkText("Manage")).Click(); s.Driver.FindElement(By.Id("WalletSend")).Click(); - s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); + s.Driver.FindElement(By.Id("SignTransaction")).Click(); //you cannot use the Sign with NBX option without saving private keys when generating the wallet. Assert.DoesNotContain("nbx-seed", s.Driver.PageSource); @@ -839,36 +838,24 @@ namespace BTCPayServer.Tests // We setup the fingerprint and the account key path s.Driver.FindElement(By.Id("WalletSettings")).Click(); - // s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160"); - // s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter); // Check the tx sent earlier arrived s.Driver.FindElement(By.Id("WalletTransactions")).Click(); var walletTransactionLink = s.Driver.Url; Assert.Contains(tx.ToString(), s.Driver.PageSource); + + // Send to bob + s.Driver.FindElement(By.Id("WalletSend")).Click(); + var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); + SetTransactionOutput(s, 0, bob, 1); + s.Driver.FindElement(By.Id("SignTransaction")).Click(); - - void SignWith(Mnemonic signingSource) - { - // Send to bob - s.Driver.FindElement(By.Id("WalletSend")).Click(); - var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); - SetTransactionOutput(s, 0, bob, 1); - s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); - s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click(); - - // Input the seed - s.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(signingSource + Keys.Enter); - - // Broadcast - Assert.Contains(bob.ToString(), s.Driver.PageSource); - Assert.Contains("1.00000000", s.Driver.PageSource); - s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); - Assert.Equal(walletTransactionLink, s.Driver.Url); - } - - SignWith(mnemonic); + // Broadcast + Assert.Contains(bob.ToString(), s.Driver.PageSource); + Assert.Contains("1.00000000", s.Driver.PageSource); + s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); + Assert.Equal(walletTransactionLink, s.Driver.Url); s.Driver.FindElement(By.Id("Wallets")).Click(); s.Driver.FindElement(By.LinkText("Manage")).Click(); @@ -876,8 +863,7 @@ namespace BTCPayServer.Tests var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest); SetTransactionOutput(s, 0, jack, 0.01m); - s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); - s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); + s.Driver.FindElement(By.Id("SignTransaction")).Click(); Assert.Contains(jack.ToString(), s.Driver.PageSource); Assert.Contains("0.01000000", s.Driver.PageSource); @@ -990,8 +976,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-actions")).Click(); s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click(); - s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); - s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); + s.Driver.FindElement(By.Id("SignTransaction")).Click(); s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); s.FindAlertMessage(); diff --git a/BTCPayServer/Controllers/WalletsController.PSBT.cs b/BTCPayServer/Controllers/WalletsController.PSBT.cs index 639908fa1..3194eccbf 100644 --- a/BTCPayServer/Controllers/WalletsController.PSBT.cs +++ b/BTCPayServer/Controllers/WalletsController.PSBT.cs @@ -70,8 +70,7 @@ namespace BTCPayServer.Controllers return psbt; } - [HttpGet] - [Route("{walletId}/psbt")] + [HttpGet("{walletId}/psbt")] public async Task WalletPSBT([ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, WalletPSBTViewModel vm) { @@ -94,8 +93,8 @@ namespace BTCPayServer.Controllers return View(nameof(WalletPSBT), vm ?? new WalletPSBTViewModel() { CryptoCode = walletId.CryptoCode }); } - [HttpPost] - [Route("{walletId}/psbt")] + + [HttpPost("{walletId}/psbt")] public async Task WalletPSBT( [ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, @@ -120,7 +119,12 @@ namespace BTCPayServer.Controllers } vm.PSBTHex = psbt.ToHex(); - var res = await TryHandleSigningCommands(walletId, psbt, command, new SigningContextModel(psbt)); + vm.SigningContext.NBXSeedAvailable = vm.NBXSeedAvailable; + var routeBack = new Dictionary + { + {"action", nameof(WalletPSBT)}, {"walletId", walletId.ToString()} + }; + var res = await TryHandleSigningCommands(walletId, psbt, command, vm.SigningContext, routeBack); if (res != null) { return res; @@ -145,7 +149,7 @@ namespace BTCPayServer.Controllers return View(vm); } TempData[WellKnownTempData.SuccessMessage] = "PSBT updated!"; - return RedirectToWalletPSBT(new WalletPSBTViewModel() + return RedirectToWalletPSBT(new WalletPSBTViewModel { PSBT = psbt.ToBase64(), FileName = vm.FileName @@ -153,14 +157,14 @@ namespace BTCPayServer.Controllers case "broadcast": { - return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel() + return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel { SigningContext = new SigningContextModel(psbt) }); } case "combine": ModelState.Remove(nameof(vm.PSBT)); - return View(nameof(WalletPSBTCombine), new WalletPSBTCombineViewModel() { OtherPSBT = psbt.ToBase64() }); + return View(nameof(WalletPSBTCombine), new WalletPSBTCombineViewModel { OtherPSBT = psbt.ToBase64() }); case "save-psbt": return FilePSBT(psbt, vm.FileName); default: @@ -176,8 +180,7 @@ namespace BTCPayServer.Controllers return await _payjoinClient.RequestPayjoin(bip21, new PayjoinWallet(derivationSchemeSettings), psbt, cancellationToken); } - [HttpGet] - [Route("{walletId}/psbt/ready")] + [HttpGet("{walletId}/psbt/ready")] public async Task WalletPSBTReady( [ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, @@ -299,8 +302,7 @@ namespace BTCPayServer.Controllers } } - [HttpPost] - [Route("{walletId}/psbt/ready")] + [HttpPost("{walletId}/psbt/ready")] public async Task WalletPSBTReady( [ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, WalletPSBTReadyViewModel vm, string command = null, CancellationToken cancellationToken = default) @@ -450,8 +452,7 @@ namespace BTCPayServer.Controllers return File(psbt.ToBytes(), "application/octet-stream", fileName); } - [HttpPost] - [Route("{walletId}/psbt/combine")] + [HttpPost("{walletId}/psbt/combine")] public async Task WalletPSBTCombine([ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, WalletPSBTCombineViewModel vm) { @@ -477,11 +478,13 @@ namespace BTCPayServer.Controllers } private async Task TryHandleSigningCommands(WalletId walletId, PSBT psbt, string command, - SigningContextModel signingContext) + SigningContextModel signingContext, Dictionary routeBack) { signingContext.PSBT = psbt.ToBase64(); switch (command) { + case "sign": + return View("WalletSigningOptions", new WalletSigningOptionsModel(signingContext, routeBack)); case "vault": return ViewVault(walletId, signingContext); case "seed": @@ -496,10 +499,10 @@ namespace BTCPayServer.Controllers .GetMetadataAsync(derivationScheme.AccountDerivation, WellknownMetadataKeys.MasterHDKey); return SignWithSeed(walletId, - new SignWithSeedViewModel() { SeedOrKey = extKey, SigningContext = signingContext }); + new SignWithSeedViewModel { SeedOrKey = extKey, SigningContext = signingContext }); } } - TempData.SetStatusMessageModel(new StatusMessageModel() + TempData.SetStatusMessageModel(new StatusMessageModel { Severity = StatusMessageModel.StatusSeverity.Error, Message = "NBX seed functionality is not available" diff --git a/BTCPayServer/Controllers/WalletsController.cs b/BTCPayServer/Controllers/WalletsController.cs index 7549e2f6b..bf21c9045 100644 --- a/BTCPayServer/Controllers/WalletsController.cs +++ b/BTCPayServer/Controllers/WalletsController.cs @@ -423,8 +423,7 @@ namespace BTCPayServer.Controllers return (await _authorizationService.CanUseHotWallet(policies, User)).HotWallet; } - [HttpGet] - [Route("{walletId}/send")] + [HttpGet("{walletId}/send")] public async Task WalletSend( [ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, string defaultDestination = null, string defaultAmount = null, string[] bip21 = null) @@ -533,8 +532,7 @@ namespace BTCPayServer.Controllers !string.IsNullOrEmpty(seed) ? seed : null; } - [HttpPost] - [Route("{walletId}/send")] + [HttpPost("{walletId}/send")] public async Task WalletSend( [ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, WalletSendModel vm, string command = "", CancellationToken cancellation = default, string bip21 = "") @@ -544,7 +542,7 @@ namespace BTCPayServer.Controllers var store = await Repository.FindStore(walletId.StoreId, GetUserId()); if (store == null) return NotFound(); - var network = this.NetworkProvider.GetNetwork(walletId?.CryptoCode); + var network = NetworkProvider.GetNetwork(walletId?.CryptoCode); if (network == null || network.ReadonlyWallet) return NotFound(); vm.SupportRBF = network.SupportRBF; @@ -683,16 +681,14 @@ namespace BTCPayServer.Controllers "The fee rate should be above 0", this); } } - if (!ModelState.IsValid) return View(vm); - + DerivationSchemeSettings derivationScheme = GetDerivationSchemeSettings(walletId); - - CreatePSBTResponse psbt = null; + CreatePSBTResponse psbtResponse; try { - psbt = await CreatePSBT(network, derivationScheme, vm, cancellation); + psbtResponse = await CreatePSBT(network, derivationScheme, vm, cancellation); } catch (NBXplorerException ex) { @@ -704,16 +700,24 @@ namespace BTCPayServer.Controllers ModelState.AddModelError(string.Empty, "You need to update your version of NBXplorer"); return View(vm); } - derivationScheme.RebaseKeyPaths(psbt.PSBT); - var signingContext = new SigningContextModel() + var psbt = psbtResponse.PSBT; + derivationScheme.RebaseKeyPaths(psbt); + + var signingContext = new SigningContextModel { PayJoinBIP21 = vm.PayJoinBIP21, - EnforceLowR = psbt.Suggestions?.ShouldEnforceLowR, - ChangeAddress = psbt.ChangeAddress?.ToString() + EnforceLowR = psbtResponse.Suggestions?.ShouldEnforceLowR, + ChangeAddress = psbtResponse.ChangeAddress?.ToString(), + NBXSeedAvailable = vm.NBXSeedAvailable + }; + + var routeBack = new Dictionary + { + {"action", nameof(WalletSend)}, {"walletId", walletId.ToString()} }; - var res = await TryHandleSigningCommands(walletId, psbt.PSBT, command, signingContext); + var res = await TryHandleSigningCommands(walletId, psbt, command, signingContext, routeBack); if (res != null) { return res; @@ -724,15 +728,14 @@ namespace BTCPayServer.Controllers case "analyze-psbt": var name = $"Send-{string.Join('_', vm.Outputs.Select(output => $"{output.Amount}->{output.DestinationAddress}{(output.SubtractFeesFromOutput ? "-Fees" : string.Empty)}"))}.psbt"; - return RedirectToWalletPSBT(new WalletPSBTViewModel() + return RedirectToWalletPSBT(new WalletPSBTViewModel { - PSBT = psbt.PSBT.ToBase64(), + PSBT = psbt.ToBase64(), FileName = name }); default: return View(vm); } - } private void LoadFromBIP21(WalletSendModel vm, string bip21, BTCPayNetwork network) diff --git a/BTCPayServer/Models/WalletViewModels/SigningContextModel.cs b/BTCPayServer/Models/WalletViewModels/SigningContextModel.cs index b123c27f3..15b10a2f7 100644 --- a/BTCPayServer/Models/WalletViewModels/SigningContextModel.cs +++ b/BTCPayServer/Models/WalletViewModels/SigningContextModel.cs @@ -17,5 +17,6 @@ namespace BTCPayServer.Models.WalletViewModels public string PayJoinBIP21 { get; set; } public bool? EnforceLowR { get; set; } public string ChangeAddress { get; set; } + public bool NBXSeedAvailable { get; set; } } } diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs index 8f4ea0455..69f166861 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs @@ -34,6 +34,8 @@ 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 GetPSBT(Network network) { if (UploadedPSBTFile != null) @@ -56,6 +58,10 @@ namespace BTCPayServer.Models.WalletViewModels PSBT = await stream.ReadToEndAsync(); } } + if (SigningContext != null && !string.IsNullOrEmpty(SigningContext.PSBT)) + { + PSBT = SigningContext.PSBT; + } if (!string.IsNullOrEmpty(PSBT)) { try diff --git a/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs new file mode 100644 index 000000000..f3f46d93d --- /dev/null +++ b/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace BTCPayServer.Models.WalletViewModels +{ + public class WalletSigningOptionsModel + { + public WalletSigningOptionsModel( + SigningContextModel signingContext, + IDictionary routeDataBack) + { + SigningContext = signingContext; + RouteDataBack = routeDataBack; + } + + public SigningContextModel SigningContext { get; } + public IDictionary RouteDataBack { get; } + } +} diff --git a/BTCPayServer/Views/Shared/_LayoutWizard.cshtml b/BTCPayServer/Views/Shared/_LayoutWizard.cshtml new file mode 100644 index 000000000..99ec4779d --- /dev/null +++ b/BTCPayServer/Views/Shared/_LayoutWizard.cshtml @@ -0,0 +1,26 @@ +@{ + Layout = "_LayoutSimple"; +} + +@section PageHeadContent { + + @await RenderSectionAsync("PageHeadContent", false) +} + +@section PageFootContent { + @await RenderSectionAsync("PageFootContent", false) +} + + + +
+
+ + @RenderBody() +
+
+ + + diff --git a/BTCPayServer/Views/Stores/GenerateWalletOptions.cshtml b/BTCPayServer/Views/Stores/GenerateWalletOptions.cshtml index 95c8ab873..d5f832471 100644 --- a/BTCPayServer/Views/Stores/GenerateWalletOptions.cshtml +++ b/BTCPayServer/Views/Stores/GenerateWalletOptions.cshtml @@ -16,7 +16,7 @@
@if (Model.CanUseHotWallet) { - +
@@ -33,7 +33,7 @@ } else { -
+
@@ -46,7 +46,7 @@
- +
diff --git a/BTCPayServer/Views/Stores/ImportWalletOptions.cshtml b/BTCPayServer/Views/Stores/ImportWalletOptions.cshtml index f772a0053..01074c450 100644 --- a/BTCPayServer/Views/Stores/ImportWalletOptions.cshtml +++ b/BTCPayServer/Views/Stores/ImportWalletOptions.cshtml @@ -21,7 +21,7 @@ {
- +
@@ -35,7 +35,7 @@