diff --git a/BTCPayServer.Client/BTCPayServer.Client.csproj b/BTCPayServer.Client/BTCPayServer.Client.csproj index 7ee47c484..d92e2bd7e 100644 --- a/BTCPayServer.Client/BTCPayServer.Client.csproj +++ b/BTCPayServer.Client/BTCPayServer.Client.csproj @@ -29,7 +29,7 @@ - + diff --git a/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs b/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs index a02837914..6d7e6a404 100644 --- a/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs +++ b/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs @@ -1,5 +1,6 @@ using BTCPayServer.Client.JsonConverters; using BTCPayServer.JsonConverters; +using BTCPayServer.Lightning; using NBitcoin; using Newtonsoft.Json; @@ -15,5 +16,8 @@ namespace BTCPayServer.Client.Models [JsonConverter(typeof(MoneyJsonConverter))] public Money MaxFeeFlat { get; set; } + + [JsonConverter(typeof(LightMoneyJsonConverter))] + public LightMoney Amount { get; set; } } } diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 4d3db7bb7..53a136e5d 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -1518,11 +1518,9 @@ namespace BTCPayServer.Tests var lnurlResponse2 = await fetchedReuqest.SendRequest(new LightMoney(0.000002m, LightMoneyUnit.BTC), network, new HttpClient(), comment: "lol2"); Assert.Equal(new LightMoney(0.000002m, LightMoneyUnit.BTC), lnurlResponse2.GetPaymentRequest(network).MinimumAmount); - await Assert.ThrowsAnyAsync(async () => - { - // Initial bolt was cancelled - await s.Server.CustomerLightningD.Pay(lnurlResponse.Pr); - }); + // Initial bolt was cancelled + var res = await s.Server.CustomerLightningD.Pay(lnurlResponse.Pr); + Assert.Equal(PayResult.Error, res.Result); await s.Server.CustomerLightningD.Pay(lnurlResponse2.Pr); await TestUtils.EventuallyAsync(async () => diff --git a/BTCPayServer.Tests/ServerTester.cs b/BTCPayServer.Tests/ServerTester.cs index 84e8a6fc5..a46fef0df 100644 --- a/BTCPayServer.Tests/ServerTester.cs +++ b/BTCPayServer.Tests/ServerTester.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; -using System.Runtime.CompilerServices; using System.Threading.Tasks; using BTCPayServer.Lightning; using BTCPayServer.Lightning.CLightning; @@ -174,11 +173,11 @@ namespace BTCPayServer.Tests SendLightningPaymentAsync(invoice).GetAwaiter().GetResult(); } - public async Task SendLightningPaymentAsync(Invoice invoice) + public async Task SendLightningPaymentAsync(Invoice invoice) { var bolt11 = invoice.CryptoInfo.Where(o => o.PaymentUrls.BOLT11 != null).First().PaymentUrls.BOLT11; bolt11 = bolt11.Replace("lightning:", "", StringComparison.OrdinalIgnoreCase); - await CustomerLightningD.Pay(bolt11); + return await CustomerLightningD.Pay(bolt11); } public async Task WaitForEvent(Func action, Func correctEvent = null) diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 25e2dffdd..9d808365b 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -5,8 +5,6 @@ using System.IO; using System.Linq; using System.Net; using System.Net.Http; -using System.Runtime.CompilerServices; -using System.Security; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -17,7 +15,6 @@ using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; using BTCPayServer.Client; using BTCPayServer.Client.Models; -using BTCPayServer.Configuration; using BTCPayServer.Controllers; using BTCPayServer.Data; using BTCPayServer.Events; @@ -26,7 +23,6 @@ using BTCPayServer.Fido2.Models; using BTCPayServer.HostedServices; using BTCPayServer.Hosting; using BTCPayServer.Lightning; -using BTCPayServer.Lightning.CLightning; using BTCPayServer.Models; using BTCPayServer.Models.AccountViewModels; using BTCPayServer.Models.AppViewModels; @@ -39,33 +35,26 @@ using BTCPayServer.Payments; using BTCPayServer.Payments.Bitcoin; using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.PayJoin.Sender; -using BTCPayServer.Rating; using BTCPayServer.Security.Bitpay; using BTCPayServer.Services; using BTCPayServer.Services.Apps; using BTCPayServer.Services.Invoices; -using BTCPayServer.Services.Labels; using BTCPayServer.Services.Mails; using BTCPayServer.Services.Rates; using BTCPayServer.Storage.Models; using BTCPayServer.Storage.Services.Providers.FileSystemStorage.Configuration; using BTCPayServer.Storage.ViewModels; -using BTCPayServer.Tests.Logging; -using BTCPayServer.Validation; using ExchangeSharp; using Fido2NetLib; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NBitcoin; using NBitcoin.DataEncoders; using NBitcoin.Payment; -using NBitcoin.Socks; using NBitpayClient; using NBXplorer; -using NBXplorer.DerivationStrategy; using NBXplorer.Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -390,11 +379,9 @@ namespace BTCPayServer.Tests Assert.Equal(InvoiceExceptionStatus.None, fetchedInvoice.ExceptionStatus); //BTCPay will attempt to cancel previous bolt11 invoices so that there are less weird edge case scenarios - TestLogs.LogInformation($"Attempting to pay invoice {invoice.Id} original full amount bolt11 invoice "); - await Assert.ThrowsAsync(async () => - { - await tester.SendLightningPaymentAsync(invoice); - }); + TestLogs.LogInformation($"Attempting to pay invoice {invoice.Id} original full amount bolt11 invoice"); + var res = await tester.SendLightningPaymentAsync(invoice); + Assert.Equal(PayResult.Error, res.Result); //NOTE: Eclair does not support cancelling invoice so the below test case would make sense for it // TestLogs.LogInformation($"Paying invoice {invoice.Id} original full amount bolt11 invoice "); diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 14565b37d..de25650cc 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -48,7 +48,7 @@ - + diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs index fda96aa8a..bd1d16185 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs @@ -6,10 +6,8 @@ using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Client; using BTCPayServer.Client.Models; -using BTCPayServer.HostedServices; using BTCPayServer.Lightning; using BTCPayServer.Security; -using BTCPayServer.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -187,8 +185,8 @@ namespace BTCPayServer.Controllers.Greenfield return this.CreateValidationError(ModelState); } - var param = lightningInvoice?.MaxFeeFlat != null || lightningInvoice?.MaxFeePercent != null - ? new PayInvoiceParams { MaxFeePercent = lightningInvoice.MaxFeePercent, MaxFeeFlat = lightningInvoice.MaxFeeFlat } + var param = lightningInvoice?.MaxFeeFlat != null || lightningInvoice?.MaxFeePercent != null || lightningInvoice?.Amount != null + ? new PayInvoiceParams { MaxFeePercent = lightningInvoice.MaxFeePercent, MaxFeeFlat = lightningInvoice.MaxFeeFlat, Amount = lightningInvoice.Amount } : null; var result = await lightningClient.Pay(lightningInvoice.BOLT11, param, cancellationToken); diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json index 6214eafdf..0878e3916 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json @@ -204,6 +204,11 @@ "type": "string", "description": "The BOLT11 of the invoice to pay" }, + "amount": { + "type": "string", + "description": "Optional explicit payment amount in millisatoshi (if specified, it overrides the BOLT11 amount)", + "nullable": true + }, "maxFeePercent": { "type": "string", "format": "float",