diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index fb4402e42..356de52e0 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -544,6 +544,7 @@ namespace BTCPayServer.Tests } } Driver.Navigate().Refresh(); + Driver.FindElement(By.Id("CancelWizard")).Click(); return addressStr; } diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index f7fd148de..78b01b83f 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -11,7 +11,6 @@ using BTCPayServer.Abstractions.Models; using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.Lightning; -using BTCPayServer.Lightning.CLightning; using BTCPayServer.Payments; using BTCPayServer.Services; using BTCPayServer.Services.Invoices; @@ -94,9 +93,8 @@ namespace BTCPayServer.Tests s.Driver.SetCheckbox(By.Id("selectAllCheckbox"), true); s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click(); s.Driver.FindElement(By.Id("BumpFee")).Click(); - var err = s.FindAlertMessage(StatusMessageModel.StatusSeverity.Error); - Assert.Contains("any UTXO available", err.Text); Assert.Contains($"/stores/{s.StoreId}/invoices", s.Driver.Url); + Assert.Contains("any UTXO available", s.FindAlertMessage(StatusMessageModel.StatusSeverity.Error).Text); // But we should be able to bump from the wallet's page s.GoToWallet(navPages: WalletsNavPages.Transactions); @@ -104,8 +102,8 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click(); s.Driver.FindElement(By.Id("BumpFee")).Click(); s.Driver.FindElement(By.Id("BroadcastTransaction")).Click(); - s.FindAlertMessage(); Assert.Contains($"/wallets/{s.WalletId}", s.Driver.Url); + Assert.Contains("Transaction broadcasted successfully", s.FindAlertMessage().Text); } [Fact(Timeout = TestTimeout)] @@ -1046,6 +1044,7 @@ namespace BTCPayServer.Tests //you cannot use the Sign with NBX option without saving private keys when generating the wallet. Assert.DoesNotContain("nbx-seed", s.Driver.PageSource); + s.Driver.FindElement(By.Id("CancelWizard")).Click(); s.Driver.FindElement(By.Id("WalletNav-Receive")).Click(); //generate a receiving address s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click(); @@ -1070,6 +1069,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click(); Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("address")).GetAttribute("value")); receiveAddr = s.Driver.FindElement(By.Id("address")).GetAttribute("value"); + s.Driver.FindElement(By.Id("CancelWizard")).Click(); //change the wallet and ensure old address is not there and generating a new one does not result in the prev one s.GenerateWallet(cryptoCode, "", true); @@ -1164,6 +1164,7 @@ namespace BTCPayServer.Tests Assert.Equal(parsedBip21.Address.ToString(), s.Driver.FindElement(By.Id("Outputs_0__DestinationAddress")).GetAttribute("value")); + s.Driver.FindElement(By.Id("CancelWizard")).Click(); s.GoToWalletSettings(cryptoCode); var settingsUrl = s.Driver.Url; s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click(); @@ -1299,6 +1300,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); s.FindAlertMessage(); + s.GoToWallet(null, WalletsNavPages.Transactions); TestUtils.Eventually(() => { s.Driver.Navigate().Refresh(); diff --git a/BTCPayServer/Controllers/UIWalletsController.PSBT.cs b/BTCPayServer/Controllers/UIWalletsController.PSBT.cs index 799dda729..a32401684 100644 --- a/BTCPayServer/Controllers/UIWalletsController.PSBT.cs +++ b/BTCPayServer/Controllers/UIWalletsController.PSBT.cs @@ -13,6 +13,7 @@ using BTCPayServer.Models; using BTCPayServer.Models.WalletViewModels; using BTCPayServer.Payments.PayJoin.Sender; using BTCPayServer.Services; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using NBitcoin; using NBitcoin.Payment; @@ -23,7 +24,6 @@ namespace BTCPayServer.Controllers { public partial class UIWalletsController { - [NonAction] public async Task CreatePSBT(BTCPayNetwork network, DerivationSchemeSettings derivationSettings, WalletSendModel sendModel, CancellationToken cancellationToken) { @@ -132,16 +132,17 @@ namespace BTCPayServer.Controllers return View("PostRedirect", new PostRedirectViewModel { AspController = "UIWallets", - AspAction = nameof(UIWalletsController.WalletSign), + AspAction = nameof(WalletSign), RouteParameters = { - { "walletId", walletId.ToString() }, - { "returnUrl", returnUrl } + { "walletId", walletId.ToString() } }, FormParameters = - { - { "walletId", walletId.ToString() }, - { "psbt", psbt.ToHex() } - } + { + { "walletId", walletId.ToString() }, + { "psbt", psbt.ToHex() }, + { "backUrl", returnUrl }, + { "returnUrl", returnUrl } + } }); } catch (Exception ex) { TempData[WellKnownTempData.ErrorMessage] = ex.Message; @@ -152,23 +153,29 @@ namespace BTCPayServer.Controllers [HttpPost("{walletId}/sign")] public async Task WalletSign([ModelBinder(typeof(WalletIdModelBinder))] - WalletId walletId, WalletPSBTViewModel vm, string returnUrl = null, string command = null) + WalletId walletId, WalletPSBTViewModel vm, string command = null) { var network = NetworkProvider.GetNetwork(walletId.CryptoCode); - if (returnUrl is null) - returnUrl = Url.Action(nameof(WalletTransactions), new { walletId }); var psbt = await vm.GetPSBT(network.NBitcoinNetwork); + + vm.BackUrl ??= HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath; + if (psbt is null || vm.InvalidPSBT) { ModelState.AddModelError(nameof(vm.PSBT), "Invalid PSBT"); - return View("WalletSigningOptions", new WalletSigningOptionsModel(vm.SigningContext, returnUrl)); + return View("WalletSigningOptions", new WalletSigningOptionsModel + { + SigningContext = vm.SigningContext, + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl + }); } switch (command) { case "vault": - return ViewVault(walletId, vm.SigningContext); + return ViewVault(walletId, vm); case "seed": - return SignWithSeed(walletId, vm.SigningContext); + return SignWithSeed(walletId, vm.SigningContext, vm.ReturnUrl, vm.BackUrl); case "decode": return await WalletPSBT(walletId, vm, "decode"); default: @@ -185,21 +192,36 @@ namespace BTCPayServer.Controllers WellknownMetadataKeys.MasterHDKey); if (extKey != null) { - return await SignWithSeed(walletId, - new SignWithSeedViewModel { SeedOrKey = extKey, SigningContext = vm.SigningContext }); + return await SignWithSeed(walletId, new SignWithSeedViewModel + { + SeedOrKey = extKey, + SigningContext = vm.SigningContext, + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl + }); } } } - return View("WalletSigningOptions", new WalletSigningOptionsModel(vm.SigningContext, returnUrl)); + return View("WalletSigningOptions", new WalletSigningOptionsModel + { + SigningContext = vm.SigningContext, + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl + }); } [HttpGet("{walletId}/psbt")] public async Task WalletPSBT([ModelBinder(typeof(WalletIdModelBinder))] - WalletId walletId) + WalletId walletId, string returnUrl) { var network = NetworkProvider.GetNetwork(walletId.CryptoCode); - var vm = new WalletPSBTViewModel(); - vm.CryptoCode = network.CryptoCode; + var referer = HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath; + var vm = new WalletPSBTViewModel + { + BackUrl = string.IsNullOrEmpty(returnUrl) ? null : referer, + ReturnUrl = returnUrl ?? referer, + CryptoCode = network.CryptoCode + }; var derivationSchemeSettings = GetDerivationSchemeSettings(walletId); if (derivationSchemeSettings == null) @@ -222,6 +244,8 @@ namespace BTCPayServer.Controllers return NotFound(); vm.NBXSeedAvailable = await CanUseHotWallet() && derivationSchemeSettings.IsHotWallet; + vm.BackUrl ??= HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath; + var psbt = await vm.GetPSBT(network.NBitcoinNetwork); if (vm.InvalidPSBT) { @@ -257,20 +281,27 @@ namespace BTCPayServer.Controllers return RedirectToWalletPSBT(new WalletPSBTViewModel { PSBT = psbt.ToBase64(), - FileName = vm.FileName + FileName = vm.FileName, + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl }); 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(), + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl + }); case "broadcast": + return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel { - return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel - { - SigningContext = new SigningContextModel(psbt) - }); - } + SigningContext = new SigningContextModel(psbt), + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl + }); default: return View("WalletPSBTDecoded", vm); @@ -452,7 +483,7 @@ namespace BTCPayServer.Controllers }); vm.SigningContext.PSBT = proposedPayjoin.ToBase64(); vm.SigningContext.OriginalPSBT = psbt.ToBase64(); - return ViewVault(walletId, vm.SigningContext); + return ViewVault(walletId, vm); } } catch (PayjoinReceiverException ex) @@ -523,17 +554,18 @@ namespace BTCPayServer.Controllers { TempData[WellKnownTempData.SuccessMessage] = $"Transaction broadcasted successfully ({transaction.GetHash()})"; } - var returnUrl = this.HttpContext.Request.Query["returnUrl"].FirstOrDefault(); - if (returnUrl is not null) + if (!string.IsNullOrEmpty(vm.ReturnUrl)) { - return LocalRedirect(returnUrl); + return LocalRedirect(vm.ReturnUrl); } return RedirectToAction(nameof(WalletTransactions), new { walletId = walletId.ToString() }); } case "analyze-psbt": - return RedirectToWalletPSBT(new WalletPSBTViewModel() + return RedirectToWalletPSBT(new WalletPSBTViewModel { - PSBT = psbt.ToBase64() + PSBT = psbt.ToBase64(), + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl }); case "decode": await FetchTransactionDetails(derivationSchemeSettings, vm, network); @@ -568,9 +600,10 @@ namespace BTCPayServer.Controllers } sourcePSBT = sourcePSBT.Combine(psbt); TempData[WellKnownTempData.SuccessMessage] = "PSBT Successfully combined!"; - return RedirectToWalletPSBT(new WalletPSBTViewModel() + return RedirectToWalletPSBT(new WalletPSBTViewModel { - PSBT = sourcePSBT.ToBase64() + PSBT = sourcePSBT.ToBase64(), + ReturnUrl = vm.ReturnUrl }); } } diff --git a/BTCPayServer/Controllers/UIWalletsController.cs b/BTCPayServer/Controllers/UIWalletsController.cs index 531dcede6..eed46829f 100644 --- a/BTCPayServer/Controllers/UIWalletsController.cs +++ b/BTCPayServer/Controllers/UIWalletsController.cs @@ -31,6 +31,7 @@ using NBitcoin; using BTCPayServer.Client.Models; using BTCPayServer.Logging; using BTCPayServer.Services.Wallets.Export; +using Microsoft.AspNetCore.Http; using NBXplorer; using NBXplorer.Client; using NBXplorer.DerivationStrategy; @@ -349,7 +350,8 @@ namespace BTCPayServer.Controllers } [HttpGet("{walletId}/receive")] - public IActionResult WalletReceive([ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId) + public IActionResult WalletReceive([ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, + [FromQuery] string returnUrl = null) { if (walletId?.StoreId == null) return NotFound(); @@ -369,26 +371,26 @@ namespace BTCPayServer.Controllers Request.GetAbsoluteUri(Url.Action(nameof(PayJoinEndpointController.Submit), "PayJoinEndpoint", new { walletId.CryptoCode }))); } - return View(new WalletReceiveViewModel() + return View(new WalletReceiveViewModel { CryptoCode = walletId.CryptoCode, Address = address?.ToString(), CryptoImage = GetImage(paymentMethod.PaymentId, network), - PaymentLink = bip21.ToString() + PaymentLink = bip21.ToString(), + ReturnUrl = returnUrl ?? HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath }); } - [HttpPost] - [Route("{walletId}/receive")] + [HttpPost("{walletId}/receive")] public async Task WalletReceive([ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, - WalletReceiveViewModel viewModel, string command) + WalletReceiveViewModel vm, string command) { if (walletId?.StoreId == null) return NotFound(); DerivationSchemeSettings paymentMethod = GetDerivationSchemeSettings(walletId); if (paymentMethod == null) return NotFound(); - var network = this.NetworkProvider.GetNetwork(walletId?.CryptoCode); + var network = NetworkProvider.GetNetwork(walletId?.CryptoCode); if (network == null) return NotFound(); switch (command) @@ -397,7 +399,7 @@ namespace BTCPayServer.Controllers var address = await _walletReceiveService.UnReserveAddress(walletId); if (!string.IsNullOrEmpty(address)) { - TempData.SetStatusMessageModel(new StatusMessageModel() + TempData.SetStatusMessageModel(new StatusMessageModel { AllowDismiss = true, Message = $"Address {address} was unreserved.", @@ -414,7 +416,7 @@ namespace BTCPayServer.Controllers await SendFreeMoney(cheater, walletId, paymentMethod); break; } - return RedirectToAction(nameof(WalletReceive), new { walletId }); + return RedirectToAction(nameof(WalletReceive), new { walletId, returnUrl = vm.ReturnUrl }); } private async Task SendFreeMoney(Cheater cheater, WalletId walletId, DerivationSchemeSettings paymentMethod) @@ -458,8 +460,9 @@ namespace BTCPayServer.Controllers [HttpGet("{walletId}/send")] public async Task WalletSend( - [ModelBinder(typeof(WalletIdModelBinder))] - WalletId walletId, string defaultDestination = null, string defaultAmount = null, string[] bip21 = null) + [ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, + string defaultDestination = null, string defaultAmount = null, string[] bip21 = null, + [FromQuery] string returnUrl = null) { if (walletId?.StoreId == null) return NotFound(); @@ -475,7 +478,12 @@ namespace BTCPayServer.Controllers rateRules.Spread = 0.0m; var currencyPair = new Rating.CurrencyPair(paymentMethod.PaymentId.CryptoCode, storeData.DefaultCurrency); double.TryParse(defaultAmount, out var amount); - var model = new WalletSendModel() { CryptoCode = walletId.CryptoCode }; + + var model = new WalletSendModel + { + CryptoCode = walletId.CryptoCode, + ReturnUrl = returnUrl ?? HttpContext.Request.GetTypedHeaders().Referer?.AbsolutePath + }; if (bip21?.Any() is true) { foreach (var link in bip21) @@ -590,6 +598,7 @@ namespace BTCPayServer.Controllers var network = NetworkProvider.GetNetwork(walletId?.CryptoCode); if (network == null || network.ReadonlyWallet) return NotFound(); + vm.SupportRBF = network.SupportRBF; vm.NBXSeedAvailable = await GetSeed(walletId, network) != null; if (!string.IsNullOrEmpty(bip21)) @@ -857,7 +866,12 @@ namespace BTCPayServer.Controllers switch (command) { case "sign": - return await WalletSign(walletId, new WalletPSBTViewModel() { SigningContext = signingContext }); + return await WalletSign(walletId, new WalletPSBTViewModel + { + SigningContext = signingContext, + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl + }); case "analyze-psbt": var name = $"Send-{string.Join('_', vm.Outputs.Select(output => $"{output.Amount}->{output.DestinationAddress}{(output.SubtractFeesFromOutput ? "-Fees" : string.Empty)}"))}.psbt"; @@ -920,24 +934,30 @@ namespace BTCPayServer.Controllers ModelState.Clear(); } - private IActionResult ViewVault(WalletId walletId, SigningContextModel signingContext) + private IActionResult ViewVault(WalletId walletId, WalletPSBTViewModel vm) { return View(nameof(WalletSendVault), - new WalletSendVaultModel() + new WalletSendVaultModel { - SigningContext = signingContext, + SigningContext = vm.SigningContext, WalletId = walletId.ToString(), - WebsocketPath = this.Url.Action(nameof(UIVaultController.VaultBridgeConnection), "UIVault", - new { walletId = walletId.ToString() }) + WebsocketPath = Url.Action(nameof(UIVaultController.VaultBridgeConnection), "UIVault", + new { walletId = walletId.ToString() }), + ReturnUrl = vm.ReturnUrl, + BackUrl = vm.BackUrl }); } - [HttpPost] - [Route("{walletId}/vault")] + [HttpPost("{walletId}/vault")] public IActionResult WalletSendVault([ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, WalletSendVaultModel model) { - return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel() { SigningContext = model.SigningContext }); + return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel + { + SigningContext = model.SigningContext, + ReturnUrl = model.ReturnUrl, + BackUrl = model.BackUrl + }); } private IActionResult RedirectToWalletPSBTReady(WalletPSBTReadyViewModel vm) @@ -962,9 +982,13 @@ namespace BTCPayServer.Controllers redirectVm.FormParameters.Remove("command"); redirectVm.FormParameters.Add("command", "broadcast"); } - if (this.HttpContext.Request.Query["returnUrl"].FirstOrDefault() is string returnUrl) + if (vm.ReturnUrl != null) { - redirectVm.RouteParameters.Add("returnUrl", returnUrl); + redirectVm.FormParameters.Add("returnUrl", vm.ReturnUrl); + } + if (vm.BackUrl != null) + { + redirectVm.FormParameters.Add("backUrl", vm.BackUrl); } return View("PostRedirect", redirectVm); } @@ -987,17 +1011,29 @@ namespace BTCPayServer.Controllers { AspController = "UIWallets", AspAction = nameof(WalletPSBT), - RouteParameters = { { "walletId", this.RouteData?.Values["walletId"]?.ToString() } }, - FormParameters = { { "psbt", vm.PSBT }, { "fileName", vm.FileName }, { "command", "decode" }, } + RouteParameters = { { "walletId", RouteData.Values["walletId"]?.ToString() } }, + FormParameters = + { + { "psbt", vm.PSBT }, + { "fileName", vm.FileName }, + { "backUrl", vm.BackUrl }, + { "returnUrl", vm.ReturnUrl }, + { "command", "decode" } + } }; return View("PostRedirect", redirectVm); } [HttpGet("{walletId}/psbt/seed")] public IActionResult SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))] WalletId walletId, - SigningContextModel signingContext) + SigningContextModel signingContext, string returnUrl, string backUrl) { - return View(nameof(SignWithSeed), new SignWithSeedViewModel { SigningContext = signingContext }); + return View(nameof(SignWithSeed), new SignWithSeedViewModel + { + SigningContext = signingContext, + ReturnUrl = returnUrl, + BackUrl = backUrl + }); } [HttpPost("{walletId}/psbt/seed")] @@ -1082,7 +1118,9 @@ namespace BTCPayServer.Controllers { SigningKey = signingKey.GetWif(network.NBitcoinNetwork).ToString(), SigningKeyPath = rootedKeyPath?.ToString(), - SigningContext = viewModel.SigningContext + SigningContext = viewModel.SigningContext, + ReturnUrl = viewModel.ReturnUrl, + BackUrl = viewModel.BackUrl }); } @@ -1225,12 +1263,14 @@ namespace BTCPayServer.Controllers i++; } - parameters.Add("returnUrl", Url.Action(nameof(WalletTransactions), new { walletId })); + var backUrl = Url.Action(nameof(WalletTransactions), new { walletId }); + parameters.Add("returnUrl", backUrl); + parameters.Add("backUrl", backUrl); return View("PostRedirect", new PostRedirectViewModel { AspController = "UIWallets", - AspAction = nameof(UIWalletsController.WalletCPFP), + AspAction = nameof(WalletCPFP), RouteParameters = { { "walletId", walletId.ToString() } }, FormParameters = parameters }); @@ -1324,6 +1364,7 @@ namespace BTCPayServer.Controllers public string CryptoCode { get; set; } public string Address { get; set; } public string PaymentLink { get; set; } + public string? ReturnUrl { get; set; } } public class SendToAddressResult diff --git a/BTCPayServer/Models/WalletViewModels/SignWithSeedViewModel.cs b/BTCPayServer/Models/WalletViewModels/SignWithSeedViewModel.cs index 5d713dbb0..21c92d68f 100644 --- a/BTCPayServer/Models/WalletViewModels/SignWithSeedViewModel.cs +++ b/BTCPayServer/Models/WalletViewModels/SignWithSeedViewModel.cs @@ -14,6 +14,9 @@ namespace BTCPayServer.Models.WalletViewModels [Display(Name = "Optional seed passphrase")] public string Passphrase { get; set; } + + public string BackUrl { get; set; } + public string ReturnUrl { get; set; } public ExtKey GetExtKey(Network network) { diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs index 5b8fe1efc..1d4a6697f 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletPSBTCombineViewModel.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -12,6 +13,9 @@ namespace BTCPayServer.Models.WalletViewModels public string PSBT { get; set; } [Display(Name = "Upload PSBT from file...")] public IFormFile UploadedPSBTFile { get; set; } + + public string BackUrl { get; set; } + public string ReturnUrl { get; set; } public PSBT GetSourcePSBT(Network network) { diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTReadyViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTReadyViewModel.cs index 776179101..effb866ad 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletPSBTReadyViewModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletPSBTReadyViewModel.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using NBitcoin; @@ -31,6 +32,8 @@ namespace BTCPayServer.Models.WalletViewModels public List Destinations { get; set; } = new List(); public List Inputs { get; set; } = new List(); public string FeeRate { get; set; } + public string BackUrl { get; set; } + public string ReturnUrl { get; set; } internal void SetErrors(IList errors) { diff --git a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs b/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs index 5ec47f6eb..88b16a929 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletPSBTViewModel.cs @@ -51,6 +51,7 @@ namespace BTCPayServer.Models.WalletViewModels return psbt; } public bool InvalidPSBT { get; set; } + async Task GetPSBTCore(Network network) { if (UploadedPSBTFile != null) diff --git a/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs index c984646de..f3b385779 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs @@ -67,6 +67,9 @@ namespace BTCPayServer.Models.WalletViewModels [Display(Name = "UTXOs to spend from")] public IEnumerable SelectedInputs { get; set; } + + public string BackUrl { get; set; } + public string ReturnUrl { get; set; } public class InputSelectionOption { diff --git a/BTCPayServer/Models/WalletViewModels/WalletSendVaultModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSendVaultModel.cs index 225f4cf74..5a4b00b1e 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletSendVaultModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletSendVaultModel.cs @@ -4,6 +4,8 @@ namespace BTCPayServer.Models.WalletViewModels { public string WalletId { get; set; } public string WebsocketPath { get; set; } - public SigningContextModel SigningContext { get; set; } = new SigningContextModel(); + public string BackUrl { get; set; } + public string ReturnUrl { get; set; } + public SigningContextModel SigningContext { get; set; } = new (); } } diff --git a/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs index 1436bf329..b8eecd149 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletSigningOptionsModel.cs @@ -1,18 +1,11 @@ -using System.Collections.Generic; +using System; namespace BTCPayServer.Models.WalletViewModels { public class WalletSigningOptionsModel { - public WalletSigningOptionsModel( - SigningContextModel signingContext, - string returnUrl) - { - SigningContext = signingContext; - ReturnUrl = returnUrl; - } - - public SigningContextModel SigningContext { get; } - public string ReturnUrl { get; } + public SigningContextModel SigningContext { get; set; } + public string BackUrl { get; set; } + public string ReturnUrl { get; set; } } } diff --git a/BTCPayServer/Views/Shared/VaultElements.cshtml b/BTCPayServer/Views/Shared/VaultElements.cshtml index 3e218513a..4326bc534 100644 --- a/BTCPayServer/Views/Shared/VaultElements.cshtml +++ b/BTCPayServer/Views/Shared/VaultElements.cshtml @@ -1,12 +1,12 @@ } -

@ViewData["Title"]

+
+

@ViewData["Title"]

+

You can decode a PSBT by either pasting its content, uploading the file or scanning the wallet QR code.

+
-
-
- @if (Model.Errors != null && Model.Errors.Count != 0) - { - - } +
+ @if (Model.Errors != null && Model.Errors.Count != 0) + { + + } -

You can decode a PSBT by either pasting its content, uploading the file or scanning the wallet QR code.

-
-
- - - -
-
- - -
-
- - -
-
- -
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
diff --git a/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml b/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml index bb9b52396..1bcd51135 100644 --- a/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml +++ b/BTCPayServer/Views/UIWallets/WalletPSBTCombine.cshtml @@ -1,12 +1,22 @@ +@using BTCPayServer.Controllers +@using Microsoft.AspNetCore.Mvc.TagHelpers @model WalletPSBTCombineViewModel @{ var walletId = Context.GetRouteValue("walletId").ToString(); + var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId }); + var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null; Layout = "_LayoutWizard"; ViewData.SetActivePage(WalletsNavPages.PSBT, "Combine PSBT", walletId); } @section Navbar { - + @if (backUrl != null) + { + + + + } + } @@ -17,6 +27,8 @@
+ +
diff --git a/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml b/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml index bcd861c51..337d235f2 100644 --- a/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml +++ b/BTCPayServer/Views/UIWallets/WalletPSBTDecoded.cshtml @@ -1,13 +1,18 @@ +@using BTCPayServer.Controllers +@using BTCPayServer.TagHelpers +@using Microsoft.AspNetCore.Mvc.TagHelpers +@using BundlerMinifier.TagHelpers @model WalletPSBTViewModel @addTagHelper *, BundlerMinifier.TagHelpers @{ var walletId = Context.GetRouteValue("walletId").ToString(); + var cancelUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId }); + var backUrl = Model.BackUrl != null ? $"{Model.BackUrl}?returnUrl={Model.ReturnUrl}" : null; var isReady = !Model.HasErrors; var isSignable = !isReady; var needsExport = !isSignable && !isReady; Layout = "_LayoutWizard"; ViewData.SetActivePage(WalletsNavPages.PSBT, isReady ? "Confirm broadcasting this transaction" : "Transaction Details", walletId); - var returnUrl = this.Context.Request.Query["returnUrl"].FirstOrDefault(); } @section PageHeadContent { @@ -38,12 +43,15 @@ } @section Navbar { - @if (returnUrl is string) - { - + @if (backUrl != null) + { + + + + } + - } }
@@ -59,17 +67,21 @@ + +
- +
} else if (isReady) { -
+ + +
@if (!string.IsNullOrEmpty(Model.SigningContext?.PayJoinBIP21)) { @@ -105,6 +117,8 @@ else + +
@@ -152,6 +166,8 @@ else
+ +
@@ -180,6 +196,8 @@ else
+ +

For exporting the signed PSBT and transaction information to a wallet, update the PSBT.

For batching transactions, you can combine this PSBT with another one.

diff --git a/BTCPayServer/Views/UIWallets/WalletReceive.cshtml b/BTCPayServer/Views/UIWallets/WalletReceive.cshtml index 814080025..ff8f67772 100644 --- a/BTCPayServer/Views/UIWallets/WalletReceive.cshtml +++ b/BTCPayServer/Views/UIWallets/WalletReceive.cshtml @@ -1,9 +1,13 @@ @addTagHelper *, BundlerMinifier.TagHelpers @inject BTCPayServer.Services.BTCPayServerEnvironment env +@using BTCPayServer.Controllers +@using Microsoft.AspNetCore.Mvc.TagHelpers +@using BTCPayServer.Components.QRCode @model BTCPayServer.Controllers.WalletReceiveViewModel @{ var walletId = Context.GetRouteValue("walletId").ToString(); - Layout = "../Shared/_NavLayout.cshtml"; + var returnUrl = Model.ReturnUrl ?? Url.Action(nameof(UIWalletsController.WalletTransactions), new { walletId }); + Layout = "_LayoutWizard"; ViewData.SetActivePage(WalletsNavPages.Receive, $"Receive {Model.CryptoCode}", walletId); } @@ -12,88 +16,86 @@ } -
-
- - @if (string.IsNullOrEmpty(Model.Address)) +@section Navbar { + + + +} + +
+

@ViewData["Title"]

+
+ + + + @if (string.IsNullOrEmpty(Model.Address)) + { +
+ + @if (env.CheatMode) { -
- - @if (env.CheatMode) - { - - } -
+ } - else - { -

@Model.CryptoCode Address

-
-
+ + + @if (BTCPayNetworkProvider.GetNetwork(walletId.CryptoCode).VaultSupported) { diff --git a/BTCPayServer/Views/UIWallets/WalletsNavPages.cs b/BTCPayServer/Views/UIWallets/WalletsNavPages.cs index 5b56ed7ba..c0209fa30 100644 --- a/BTCPayServer/Views/UIWallets/WalletsNavPages.cs +++ b/BTCPayServer/Views/UIWallets/WalletsNavPages.cs @@ -5,7 +5,6 @@ namespace BTCPayServer.Views.Wallets Index, Send, Transactions, - Rescan, PSBT, Receive, Settings