diff --git a/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs b/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs index a1825faae..9e88cbfff 100644 --- a/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs +++ b/BTCPayServer.Tests/AltcoinTests/AltcoinTests.cs @@ -51,6 +51,7 @@ namespace BTCPayServer.Tests user.RegisterDerivationScheme(cryptoCode); user.RegisterDerivationScheme("LTC"); user.RegisterLightningNode(cryptoCode, LightningConnectionType.CLightning); + user.SetLNUrl("BTC", false); var btcNetwork = tester.PayTester.Networks.GetNetwork(cryptoCode); var invoice = await user.BitPay.CreateInvoiceAsync( new Invoice diff --git a/BTCPayServer.Tests/Checkoutv2Tests.cs b/BTCPayServer.Tests/Checkoutv2Tests.cs index f63b0ded6..108ba3abe 100644 --- a/BTCPayServer.Tests/Checkoutv2Tests.cs +++ b/BTCPayServer.Tests/Checkoutv2Tests.cs @@ -45,13 +45,6 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("Save")).Click(); Assert.Contains("Store successfully updated", s.FindAlertMessage().Text); - // Enable LNURL, which we will need for (non-)presence checks throughout this test - s.GoToHome(); - s.GoToLightningSettings(); - s.Driver.SetCheckbox(By.Id("LNURLEnabled"), true); - s.Driver.FindElement(By.Id("save")).Click(); - Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text); - s.GoToStore(StoreNavPages.CheckoutAppearance); s.Driver.WaitForAndClick(By.Id("Presets")); s.Driver.WaitForAndClick(By.Id("Presets_InStore")); diff --git a/BTCPayServer.Tests/ServerTester.cs b/BTCPayServer.Tests/ServerTester.cs index 611266caa..82d6cf1e6 100644 --- a/BTCPayServer.Tests/ServerTester.cs +++ b/BTCPayServer.Tests/ServerTester.cs @@ -177,7 +177,7 @@ namespace BTCPayServer.Tests public async Task SendLightningPaymentAsync(Invoice invoice) { - var bolt11 = invoice.CryptoInfo.Where(o => o.PaymentUrls.BOLT11 != null).First().PaymentUrls.BOLT11; + var bolt11 = invoice.CryptoInfo.Where(o => o.PaymentUrls?.BOLT11 != null).First().PaymentUrls.BOLT11; bolt11 = bolt11.Replace("lightning:", "", StringComparison.OrdinalIgnoreCase); return await CustomerLightningD.Pay(bolt11); } diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 74316fb81..374b1d503 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -214,6 +214,13 @@ namespace BTCPayServer.Tests get => GenerateWalletResponseV.DerivationScheme; } + public void SetLNUrl(string cryptoCode, bool activated) + { + var lnSettingsVm = GetController().LightningSettings(StoreId, cryptoCode).AssertViewModel(); + lnSettingsVm.LNURLEnabled = activated; + Assert.IsType(GetController().LightningSettings(lnSettingsVm).Result); + } + private async Task RegisterAsync(bool isAdmin = false) { var account = parent.PayTester.GetController(); diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 38e0da86f..e390b37f1 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -1635,6 +1635,7 @@ namespace BTCPayServer.Tests var cryptoCode = "BTC"; user.GrantAccess(true); user.RegisterLightningNode(cryptoCode, LightningConnectionType.Charge); + user.SetLNUrl(cryptoCode, false); var vm = user.GetController().CheckoutAppearance().AssertViewModel(); var criteria = Assert.Single(vm.PaymentMethodCriteria); Assert.Equal(new PaymentMethodId(cryptoCode, LightningPaymentType.Instance).ToString(), criteria.PaymentMethod); @@ -1649,15 +1650,12 @@ namespace BTCPayServer.Tests Price = 1.5m, Currency = "USD" }, Facade.Merchant); - Assert.Single(invoice.CryptoInfo); Assert.Equal(PaymentTypes.LightningLike.ToString(), invoice.CryptoInfo[0].PaymentType); // Activating LNUrl, we should still have only 1 payment criteria that can be set. user.RegisterLightningNode(cryptoCode, LightningConnectionType.Charge); - var lnSettingsVm = user.GetController().LightningSettings(user.StoreId, cryptoCode).AssertViewModel(); - lnSettingsVm.LNURLEnabled = true; - Assert.IsType(user.GetController().LightningSettings(lnSettingsVm).Result); + user.SetLNUrl(cryptoCode, true); vm = user.GetController().CheckoutAppearance().AssertViewModel(); criteria = Assert.Single(vm.PaymentMethodCriteria); Assert.Equal(new PaymentMethodId(cryptoCode, LightningPaymentType.Instance).ToString(), criteria.PaymentMethod); diff --git a/BTCPayServer/Controllers/UIInvoiceController.UI.cs b/BTCPayServer/Controllers/UIInvoiceController.UI.cs index c338b12cb..ad9b607f4 100644 --- a/BTCPayServer/Controllers/UIInvoiceController.UI.cs +++ b/BTCPayServer/Controllers/UIInvoiceController.UI.cs @@ -686,7 +686,7 @@ namespace BTCPayServer.Controllers if (displayedPaymentMethods.Contains(lnId) && displayedPaymentMethods.Contains(lnurlId)) displayedPaymentMethods.Remove(lnurlId); - if (paymentMethodId is not null && displayedPaymentMethods.Contains(paymentMethodId)) + if (paymentMethodId is not null && !displayedPaymentMethods.Contains(paymentMethodId)) paymentMethodId = null; if (paymentMethodId is null) { diff --git a/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs b/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs index 9059fa066..5623e91fb 100644 --- a/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs +++ b/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs @@ -50,49 +50,21 @@ namespace BTCPayServer.Payments.Lightning BTCPayNetwork network, object preparePaymentObject, IEnumerable invoicePaymentMethods) { var lnPmi = new PaymentMethodId(supportedPaymentMethod.CryptoCode, PaymentTypes.LightningLike); - if (string.IsNullOrEmpty(paymentMethod.ParentEntity.Id)) + var lnSupported = store.GetSupportedPaymentMethods(_networkProvider) + .OfType() + .SingleOrDefault(method => method.PaymentId == lnPmi); + if (lnSupported is null) { - var lnSupported = store.GetSupportedPaymentMethods(_networkProvider) - .OfType().SingleOrDefault(method => - method.PaymentId.CryptoCode == supportedPaymentMethod.CryptoCode && - method.PaymentId.PaymentType == LightningPaymentType.Instance); - - if (lnSupported is null) - { - throw new PaymentMethodUnavailableException("LNURL requires a lightning node to be configured for the store."); - } - using var cts = new CancellationTokenSource(LightningLikePaymentHandler.LightningTimeout); - try - { - var client = lnSupported.CreateLightningClient(network, Options.Value, _lightningClientFactoryService); - await client.GetInfo(cts.Token); - } - catch (OperationCanceledException) when (cts.IsCancellationRequested) - { - throw new PaymentMethodUnavailableException("The lightning node did not reply in a timely manner"); - } - - return new LNURLPayPaymentMethodDetails() - { - Activated = false, - LightningSupportedPaymentMethod = lnSupported - }; + throw new PaymentMethodUnavailableException("LNURL requires a lightning node to be configured for the store."); } + var client = lnSupported.CreateLightningClient(network, Options.Value, _lightningClientFactoryService); + var nodeInfo = (await _lightningLikePaymentHandler.GetNodeInfo(lnSupported, _networkProvider.GetNetwork(supportedPaymentMethod.CryptoCode), logs, paymentMethod.PreferOnion)).FirstOrDefault(); - var lnLightningSupportedPaymentMethod = - ((LNURLPayPaymentMethodDetails)paymentMethod.GetPaymentMethodDetails()).LightningSupportedPaymentMethod; - - NodeInfo? nodeInfo = null; - if (lnLightningSupportedPaymentMethod != null) - { - nodeInfo = (await _lightningLikePaymentHandler.GetNodeInfo(lnLightningSupportedPaymentMethod, _networkProvider.GetNetwork(supportedPaymentMethod.CryptoCode), logs, paymentMethod.PreferOnion)).FirstOrDefault(); - } - - return new LNURLPayPaymentMethodDetails + return new LNURLPayPaymentMethodDetails() { Activated = true, - LightningSupportedPaymentMethod = lnLightningSupportedPaymentMethod, + LightningSupportedPaymentMethod = lnSupported, Bech32Mode = supportedPaymentMethod.UseBech32Scheme, NodeInfo = nodeInfo?.ToString() }; diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index 9febf8052..fdd2b2326 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -213,12 +213,18 @@ namespace BTCPayServer.Services.Invoices } var paymentDestination = details.GetPaymentDestination(); string address = GetDestination(paymentMethod); - await context.AddressInvoices.AddAsync(new AddressInvoiceData() + if (address != null) { - InvoiceDataId = invoice.Id, - CreatedTime = DateTimeOffset.UtcNow, - }.Set(address, paymentMethod.GetId())); - textSearch.Add(paymentDestination); + await context.AddressInvoices.AddAsync(new AddressInvoiceData() + { + InvoiceDataId = invoice.Id, + CreatedTime = DateTimeOffset.UtcNow, + }.Set(address, paymentMethod.GetId())); + } + if (paymentDestination != null) + { + textSearch.Add(paymentDestination); + } textSearch.Add(paymentMethod.Calculate().TotalDue.ToString()); } await context.PendingInvoices.AddAsync(new PendingInvoiceData() { Id = invoice.Id });