mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
BIP21 + LNURL fix (#4616)
In case of the unified invoice, the LNURL wasn't correct — with this change we are simply reusing th one that was issued on invoice creation instead of generating it anew on the fly. Also fixes missing uppercasing for the QR code in case of non-unified QR. And removes the `lightning:` scheme from the LNURL that's displayed to the user (unifies it with what we do for Onchain and Lightning)
This commit is contained in:
@@ -33,7 +33,8 @@ namespace BTCPayServer.Tests
|
|||||||
s.CreateNewStore();
|
s.CreateNewStore();
|
||||||
s.EnableCheckoutV2();
|
s.EnableCheckoutV2();
|
||||||
s.AddLightningNode();
|
s.AddLightningNode();
|
||||||
s.AddDerivationScheme();
|
// Use non-legacy derivation scheme
|
||||||
|
s.AddDerivationScheme("BTC", "tpubDD79XF4pzhmPSJ9AyUay9YbXAeD1c6nkUqC32pnKARJH6Ja5hGUfGc76V82ahXpsKqN6UcSGXMkzR34aZq4W23C6DAdZFaVrzWqzj24F8BC");
|
||||||
|
|
||||||
// Configure store url
|
// Configure store url
|
||||||
var storeUrl = "https://satoshisteaks.com/";
|
var storeUrl = "https://satoshisteaks.com/";
|
||||||
@@ -59,9 +60,16 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
|
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
|
||||||
Assert.Contains("Bitcoin", s.Driver.FindElement(By.CssSelector(".payment-method.active")).Text);
|
Assert.Contains("Bitcoin", s.Driver.FindElement(By.CssSelector(".payment-method.active")).Text);
|
||||||
Assert.Contains("LNURL", s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Text);
|
Assert.Contains("LNURL", s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Text);
|
||||||
|
var qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||||
|
var address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||||
var payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
var payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||||
Assert.StartsWith("bitcoin:", payUrl);
|
var copyAddress = s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value");
|
||||||
|
Assert.Equal($"bitcoin:{address}", payUrl);
|
||||||
|
Assert.StartsWith("bcrt", s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value"));
|
||||||
Assert.DoesNotContain("lightning=", payUrl);
|
Assert.DoesNotContain("lightning=", payUrl);
|
||||||
|
Assert.Equal(address, copyAddress);
|
||||||
|
Assert.Equal($"bitcoin:{address.ToUpperInvariant()}", qrValue);
|
||||||
|
s.Driver.ElementDoesNotExist(By.Id("Lightning_BTC"));
|
||||||
|
|
||||||
// Switch to LNURL
|
// Switch to LNURL
|
||||||
s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Click();
|
s.Driver.FindElement(By.CssSelector(".payment-method:nth-child(2)")).Click();
|
||||||
@@ -69,18 +77,26 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||||
Assert.StartsWith("lightning:lnurl", payUrl);
|
Assert.StartsWith("lightning:lnurl", payUrl);
|
||||||
|
Assert.StartsWith("lnurl", s.Driver.WaitForElement(By.Id("Lightning_BTC")).GetAttribute("value"));
|
||||||
|
s.Driver.ElementDoesNotExist(By.Id("Address_BTC"));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Default payment method
|
// Default payment method
|
||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
|
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||||
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
|
Assert.Equal(2, s.Driver.FindElements(By.CssSelector(".payment-method")).Count);
|
||||||
Assert.Contains("Lightning", s.Driver.WaitForElement(By.CssSelector(".payment-method.active")).Text);
|
Assert.Contains("Lightning", s.Driver.WaitForElement(By.CssSelector(".payment-method.active")).Text);
|
||||||
Assert.Contains("Bitcoin", s.Driver.WaitForElement(By.CssSelector(".payment-method")).Text);
|
Assert.Contains("Bitcoin", s.Driver.WaitForElement(By.CssSelector(".payment-method")).Text);
|
||||||
|
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||||
|
address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||||
Assert.StartsWith("lightning:lnbcrt", payUrl);
|
copyAddress = s.Driver.FindElement(By.Id("Lightning_BTC_LightningLike")).GetAttribute("value");
|
||||||
|
Assert.Equal($"lightning:{address}", payUrl);
|
||||||
|
Assert.Equal(address, copyAddress);
|
||||||
|
Assert.Equal($"lightning:{address.ToUpperInvariant()}", qrValue);
|
||||||
|
s.Driver.ElementDoesNotExist(By.Id("Address_BTC"));
|
||||||
|
|
||||||
// Lightning amount in Sats
|
// Lightning amount in Sats
|
||||||
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
|
Assert.Contains("BTC", s.Driver.FindElement(By.Id("AmountDue")).Text);
|
||||||
@@ -90,6 +106,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.Driver.FindElement(By.Id("save")).Click();
|
s.Driver.FindElement(By.Id("save")).Click();
|
||||||
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
|
Assert.Contains("BTC Lightning settings successfully updated", s.FindAlertMessage().Text);
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||||
Assert.Contains("Sats", s.Driver.FindElement(By.Id("AmountDue")).Text);
|
Assert.Contains("Sats", s.Driver.FindElement(By.Id("AmountDue")).Text);
|
||||||
|
|
||||||
// Expire
|
// Expire
|
||||||
@@ -114,6 +131,7 @@ namespace BTCPayServer.Tests
|
|||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
invoiceId = s.CreateInvoice();
|
invoiceId = s.CreateInvoice();
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||||
|
|
||||||
// Details
|
// Details
|
||||||
s.Driver.ToggleCollapse("PaymentDetails");
|
s.Driver.ToggleCollapse("PaymentDetails");
|
||||||
@@ -126,7 +144,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
// Pay partial amount
|
// Pay partial amount
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
var address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||||
var amountFraction = "0.00001";
|
var amountFraction = "0.00001";
|
||||||
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(address, Network.RegTest),
|
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(address, Network.RegTest),
|
||||||
Money.Parse(amountFraction));
|
Money.Parse(amountFraction));
|
||||||
@@ -176,28 +194,55 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
invoiceId = s.CreateInvoice();
|
invoiceId = s.CreateInvoice();
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||||
|
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||||
|
address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||||
Assert.StartsWith("bitcoin:", payUrl);
|
var copyAddressOnchain = s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value");
|
||||||
|
var copyAddressLightning = s.Driver.FindElement(By.Id("Lightning_BTC")).GetAttribute("value");
|
||||||
|
Assert.StartsWith($"bitcoin:{address}?amount=", payUrl);
|
||||||
|
Assert.Contains("?amount=", payUrl);
|
||||||
Assert.Contains("&lightning=", payUrl);
|
Assert.Contains("&lightning=", payUrl);
|
||||||
|
Assert.StartsWith("bcrt", copyAddressOnchain);
|
||||||
|
Assert.Equal(address, copyAddressOnchain);
|
||||||
|
Assert.StartsWith("lnbcrt", copyAddressLightning);
|
||||||
|
Assert.StartsWith($"bitcoin:{address.ToUpperInvariant()}?amount=", qrValue);
|
||||||
|
Assert.Contains("&lightning=LNBCRT", qrValue);
|
||||||
|
|
||||||
// BIP21 with LN as default payment method
|
// BIP21 with LN as default payment method
|
||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
|
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||||
Assert.StartsWith("bitcoin:", payUrl);
|
Assert.StartsWith("bitcoin:", payUrl);
|
||||||
Assert.Contains("&lightning=lnbcrt", payUrl);
|
Assert.Contains("&lightning=lnbcrt", payUrl);
|
||||||
|
|
||||||
// BIP21 with topup invoice
|
// Ensure LNURL is enabled
|
||||||
s.GoToHome();
|
s.GoToHome();
|
||||||
|
s.GoToLightningSettings();
|
||||||
|
Assert.True(s.Driver.FindElement(By.Id("LNURLEnabled")).Selected);
|
||||||
|
Assert.True(s.Driver.FindElement(By.Id("LNURLStandardInvoiceEnabled")).Selected);
|
||||||
|
|
||||||
|
// BIP21 with topup invoice
|
||||||
invoiceId = s.CreateInvoice(amount: null);
|
invoiceId = s.CreateInvoice(amount: null);
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||||
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
|
||||||
|
qrValue = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-qr-value");
|
||||||
|
address = s.Driver.FindElement(By.CssSelector(".qr-container")).GetAttribute("data-clipboard");
|
||||||
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
|
||||||
Assert.StartsWith("bitcoin:", payUrl);
|
copyAddressOnchain = s.Driver.FindElement(By.Id("Address_BTC")).GetAttribute("value");
|
||||||
Assert.DoesNotContain("&lightning=lnurl", payUrl);
|
copyAddressLightning = s.Driver.FindElement(By.Id("Lightning_BTC")).GetAttribute("value");
|
||||||
|
Assert.StartsWith($"bitcoin:{address}", payUrl);
|
||||||
|
Assert.Contains("?lightning=lnurl", payUrl);
|
||||||
|
Assert.DoesNotContain("amount=", payUrl);
|
||||||
|
Assert.StartsWith("bcrt", copyAddressOnchain);
|
||||||
|
Assert.Equal(address, copyAddressOnchain);
|
||||||
|
Assert.StartsWith("lnurl", copyAddressLightning);
|
||||||
|
Assert.StartsWith($"bitcoin:{address.ToUpperInvariant()}?lightning=LNURL", qrValue);
|
||||||
|
|
||||||
// Expiry message should not show amount for topup invoice
|
// Expiry message should not show amount for topup invoice
|
||||||
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
|
expirySeconds = s.Driver.FindElement(By.Id("ExpirySeconds"));
|
||||||
@@ -223,6 +268,7 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
|
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
|
||||||
|
|
||||||
s.GoToInvoiceCheckout(invoiceId);
|
s.GoToInvoiceCheckout(invoiceId);
|
||||||
|
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
|
||||||
paymentInfo = s.Driver.FindElement(By.Id("PaymentInfo"));
|
paymentInfo = s.Driver.FindElement(By.Id("PaymentInfo"));
|
||||||
Assert.False(paymentInfo.Displayed);
|
Assert.False(paymentInfo.Displayed);
|
||||||
Assert.DoesNotContain("This invoice will expire in", paymentInfo.Text);
|
Assert.DoesNotContain("This invoice will expire in", paymentInfo.Text);
|
||||||
|
|||||||
@@ -1613,10 +1613,10 @@ namespace BTCPayServer.Tests
|
|||||||
var paymentMethodUnified = Assert.IsType<PaymentModel>(
|
var paymentMethodUnified = Assert.IsType<PaymentModel>(
|
||||||
Assert.IsType<ViewResult>(res).Model
|
Assert.IsType<ViewResult>(res).Model
|
||||||
);
|
);
|
||||||
Assert.StartsWith("bitcoin:", paymentMethodUnified.InvoiceBitcoinUrl);
|
Assert.StartsWith("bitcoin:bcrt", paymentMethodUnified.InvoiceBitcoinUrl);
|
||||||
Assert.StartsWith("bitcoin:", paymentMethodUnified.InvoiceBitcoinUrlQR);
|
Assert.StartsWith("bitcoin:BCRT", paymentMethodUnified.InvoiceBitcoinUrlQR);
|
||||||
Assert.Contains("&lightning=", paymentMethodUnified.InvoiceBitcoinUrl);
|
Assert.Contains("&lightning=lnbcrt", paymentMethodUnified.InvoiceBitcoinUrl);
|
||||||
Assert.Contains("&lightning=", paymentMethodUnified.InvoiceBitcoinUrlQR);
|
Assert.Contains("&lightning=LNBCRT", paymentMethodUnified.InvoiceBitcoinUrlQR);
|
||||||
|
|
||||||
// Check correct casing: Addresses in payment URI need to be …
|
// Check correct casing: Addresses in payment URI need to be …
|
||||||
// - lowercase in link version
|
// - lowercase in link version
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ namespace BTCPayServer.Controllers
|
|||||||
var enabledPaymentIds = store.GetEnabledPaymentIds(_NetworkProvider)
|
var enabledPaymentIds = store.GetEnabledPaymentIds(_NetworkProvider)
|
||||||
.Where(pmId => storeBlob.CheckoutType == CheckoutType.V1 ||
|
.Where(pmId => storeBlob.CheckoutType == CheckoutType.V1 ||
|
||||||
// Exclude LNURL for Checkout v2 + non-top up invoices
|
// Exclude LNURL for Checkout v2 + non-top up invoices
|
||||||
(pmId.PaymentType is not LNURLPayPaymentType || invoice.IsUnsetTopUp()))
|
pmId != lnurlId || invoice.IsUnsetTopUp())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
// Exclude Lightning if OnChainWithLnInvoiceFallback is active and we have both payment methods
|
// Exclude Lightning if OnChainWithLnInvoiceFallback is active and we have both payment methods
|
||||||
@@ -805,7 +805,7 @@ namespace BTCPayServer.Controllers
|
|||||||
AvailableCryptos = invoice.GetPaymentMethods()
|
AvailableCryptos = invoice.GetPaymentMethods()
|
||||||
.Where(i => i.Network != null && storeBlob.CheckoutType == CheckoutType.V1 ||
|
.Where(i => i.Network != null && storeBlob.CheckoutType == CheckoutType.V1 ||
|
||||||
// Exclude LNURL for Checkout v2 + non-top up invoices
|
// Exclude LNURL for Checkout v2 + non-top up invoices
|
||||||
i.GetId().PaymentType is not LNURLPayPaymentType || invoice.IsUnsetTopUp())
|
i.GetId() != lnurlId || invoice.IsUnsetTopUp())
|
||||||
.Select(kv =>
|
.Select(kv =>
|
||||||
{
|
{
|
||||||
var availableCryptoPaymentMethodId = kv.GetId();
|
var availableCryptoPaymentMethodId = kv.GetId();
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using BTCPayServer.Models;
|
|||||||
using BTCPayServer.Models.InvoicingModels;
|
using BTCPayServer.Models.InvoicingModels;
|
||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using NBitcoin.DataEncoders;
|
using NBitcoin.DataEncoders;
|
||||||
using NBXplorer.Models;
|
using NBXplorer.Models;
|
||||||
@@ -44,7 +43,6 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
network => Encoders.ASCII.EncodeData(
|
network => Encoders.ASCII.EncodeData(
|
||||||
network.NBitcoinNetwork.GetBech32Encoder(Bech32Type.WITNESS_PUBKEY_ADDRESS, false)
|
network.NBitcoinNetwork.GetBech32Encoder(Bech32Type.WITNESS_PUBKEY_ADDRESS, false)
|
||||||
.HumanReadablePart));
|
.HumanReadablePart));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Prepare
|
class Prepare
|
||||||
@@ -58,10 +56,11 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
StoreBlob storeBlob, IPaymentMethod paymentMethod)
|
StoreBlob storeBlob, IPaymentMethod paymentMethod)
|
||||||
{
|
{
|
||||||
var paymentMethodId = paymentMethod.GetId();
|
var paymentMethodId = paymentMethod.GetId();
|
||||||
|
var paymentMethodDetails = (BitcoinLikeOnChainPaymentMethod)paymentMethod.GetPaymentMethodDetails();
|
||||||
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
||||||
var network = _networkProvider.GetNetwork<BTCPayNetwork>(model.CryptoCode);
|
var network = _networkProvider.GetNetwork<BTCPayNetwork>(model.CryptoCode);
|
||||||
model.ShowRecommendedFee = storeBlob.ShowRecommendedFee;
|
model.ShowRecommendedFee = storeBlob.ShowRecommendedFee;
|
||||||
model.FeeRate = ((BitcoinLikeOnChainPaymentMethod)paymentMethod.GetPaymentMethodDetails()).GetFeeRate();
|
model.FeeRate = paymentMethodDetails.GetFeeRate();
|
||||||
model.PaymentMethodName = GetPaymentMethodName(network);
|
model.PaymentMethodName = GetPaymentMethodName(network);
|
||||||
|
|
||||||
string lightningFallback = null;
|
string lightningFallback = null;
|
||||||
@@ -75,11 +74,20 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var lnurl = invoiceResponse.CryptoInfo.FirstOrDefault(a =>
|
var lnurlInfo = invoiceResponse.CryptoInfo.FirstOrDefault(a =>
|
||||||
a.GetpaymentMethodId() == new PaymentMethodId(model.CryptoCode, PaymentTypes.LNURLPay));
|
a.GetpaymentMethodId() == new PaymentMethodId(model.CryptoCode, PaymentTypes.LNURLPay));
|
||||||
if (lnurl is not null)
|
if (lnurlInfo is not null)
|
||||||
{
|
{
|
||||||
lightningFallback = LNURL.LNURL.EncodeUri(new Uri(lnurl.Url), "payRequest", true).ToString();
|
lightningFallback = lnurlInfo.PaymentUrls?.AdditionalData["LNURLP"].ToObject<string>();
|
||||||
|
|
||||||
|
// This seems to be an edge case in the Selenium tests, in which the LNURLP isn't populated.
|
||||||
|
// I have come across it only in the tests and this is supposed to make them happy.
|
||||||
|
if (string.IsNullOrEmpty(lightningFallback))
|
||||||
|
{
|
||||||
|
var serverUrl = new Uri(lnurlInfo.Url[..lnurlInfo.Url.IndexOf("/i/", StringComparison.InvariantCultureIgnoreCase)]);
|
||||||
|
var uri = new Uri($"{serverUrl}{network.CryptoCode}/lnurl/pay/i/{invoiceResponse.Id}");
|
||||||
|
lightningFallback = LNURL.LNURL.EncodeUri(uri, "payRequest", true).ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(lightningFallback))
|
if (!string.IsNullOrEmpty(lightningFallback))
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
|
|
||||||
public override PaymentType PaymentType => PaymentTypes.LightningLike;
|
public override PaymentType PaymentType => PaymentTypes.LightningLike;
|
||||||
|
|
||||||
|
private const string UriScheme = "lightning:";
|
||||||
|
|
||||||
public IOptions<LightningNetworkOptions> Options { get; }
|
public IOptions<LightningNetworkOptions> Options { get; }
|
||||||
|
|
||||||
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(
|
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(
|
||||||
@@ -107,12 +109,13 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
StoreBlob storeBlob, IPaymentMethod paymentMethod)
|
StoreBlob storeBlob, IPaymentMethod paymentMethod)
|
||||||
{
|
{
|
||||||
var paymentMethodId = paymentMethod.GetId();
|
var paymentMethodId = paymentMethod.GetId();
|
||||||
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
|
||||||
var network = _networkProvider.GetNetwork<BTCPayNetwork>(model.CryptoCode);
|
var network = _networkProvider.GetNetwork<BTCPayNetwork>(model.CryptoCode);
|
||||||
|
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
||||||
|
var lnurl = cryptoInfo.PaymentUrls?.AdditionalData["LNURLP"].ToObject<string>();
|
||||||
model.PaymentMethodName = GetPaymentMethodName(network);
|
model.PaymentMethodName = GetPaymentMethodName(network);
|
||||||
model.InvoiceBitcoinUrl = cryptoInfo.PaymentUrls?.AdditionalData["LNURLP"].ToObject<string>();
|
model.BtcAddress = lnurl?.Replace(UriScheme, "");
|
||||||
model.InvoiceBitcoinUrlQR = model.InvoiceBitcoinUrl;
|
model.InvoiceBitcoinUrl = lnurl;
|
||||||
model.BtcAddress = model.InvoiceBitcoinUrl;
|
model.InvoiceBitcoinUrlQR = lnurl?.ToUpperInvariant().Replace(UriScheme.ToUpperInvariant(), UriScheme);
|
||||||
model.PeerInfo = ((LNURLPayPaymentMethodDetails)paymentMethod.GetPaymentMethodDetails()).NodeInfo;
|
model.PeerInfo = ((LNURLPayPaymentMethodDetails)paymentMethod.GetPaymentMethodDetails()).NodeInfo;
|
||||||
if (storeBlob.LightningAmountInSatoshi && model.CryptoCode == "BTC")
|
if (storeBlob.LightningAmountInSatoshi && model.CryptoCode == "BTC")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<template id="bitcoin-method-checkout-template">
|
<template id="bitcoin-method-checkout-template">
|
||||||
@await Component.InvokeAsync("UiExtensionPoint", new {location = "checkout-v2-bitcoin-pre-content", model = Model})
|
@await Component.InvokeAsync("UiExtensionPoint", new {location = "checkout-v2-bitcoin-pre-content", model = Model})
|
||||||
<div class="payment-box">
|
<div class="payment-box">
|
||||||
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-clipboard="model.btcAddress" data-clipboard-confirm-element="QR_Text_@Model.PaymentMethodId">
|
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.btcAddress" data-clipboard-confirm-element="QR_Text_@Model.PaymentMethodId">
|
||||||
<div>
|
<div>
|
||||||
<qrcode :value="model.invoiceBitcoinUrlQR" tag="div" :options="qrOptions" />
|
<qrcode :value="model.invoiceBitcoinUrlQR" tag="div" :options="qrOptions" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<template id="lightning-method-checkout-template">
|
<template id="lightning-method-checkout-template">
|
||||||
<div class="payment-box">
|
<div class="payment-box">
|
||||||
@await Component.InvokeAsync("UiExtensionPoint" , new { location="checkout-v2-lightning-pre-content", model = Model})
|
@await Component.InvokeAsync("UiExtensionPoint" , new { location="checkout-v2-lightning-pre-content", model = Model})
|
||||||
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-clipboard="model.btcAddress" data-clipboard-confirm-element="QR_Text_@Model.PaymentMethodId">
|
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.btcAddress" data-clipboard-confirm-element="QR_Text_@Model.PaymentMethodId">
|
||||||
<div>
|
<div>
|
||||||
<qrcode :value="model.invoiceBitcoinUrlQR" tag="div" :options="qrOptions" />
|
<qrcode :value="model.invoiceBitcoinUrlQR" tag="div" :options="qrOptions" />
|
||||||
</div>
|
</div>
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="model.btcAddress" class="input-group mt-3">
|
<div v-if="model.btcAddress" class="input-group mt-3">
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<input id="Address_@Model.PaymentMethodId" class="form-control-plaintext" readonly="readonly" :value="model.btcAddress">
|
<input id="Lightning_@Model.PaymentMethodId" class="form-control-plaintext" readonly="readonly" :value="model.btcAddress">
|
||||||
<label for="Address_@Model.PaymentMethodId" v-t="'lightning'"></label>
|
<label for="Lightning_@Model.PaymentMethodId" v-t="'lightning'"></label>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-link" data-clipboard-target="#Address_@Model.PaymentMethodId" :data-clipboard-confirm="$t('copy_confirm')" v-t="'copy'"></button>
|
<button type="button" class="btn btn-link" data-clipboard-target="#Lightning_@Model.PaymentMethodId" :data-clipboard-confirm="$t('copy_confirm')" v-t="'copy'"></button>
|
||||||
</div>
|
</div>
|
||||||
<a v-if="model.invoiceBitcoinUrl" class="btn btn-primary rounded-pill w-100 mt-4" target="_top"
|
<a v-if="model.invoiceBitcoinUrl" class="btn btn-primary rounded-pill w-100 mt-4" target="_top"
|
||||||
:href="model.invoiceBitcoinUrl" v-t="'pay_in_wallet'"></a>
|
:href="model.invoiceBitcoinUrl" v-t="'pay_in_wallet'"></a>
|
||||||
|
|||||||
Reference in New Issue
Block a user