Lightning: Allow specifying explicit amount for invoices (#3753)

* Upgrade Lightning lib

* Lightning: Allow specifying explicit amount for invoices

* Fix tests
This commit is contained in:
d11n 2022-05-18 07:57:36 +02:00 committed by GitHub
parent f3f605a90f
commit 6d76771b16
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 21 additions and 30 deletions

View file

@ -29,7 +29,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NBitcoin" Version="7.0.1" /> <PackageReference Include="NBitcoin" Version="7.0.1" />
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.3.2" /> <PackageReference Include="BTCPayServer.Lightning.Common" Version="1.3.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,5 +1,6 @@
using BTCPayServer.Client.JsonConverters; using BTCPayServer.Client.JsonConverters;
using BTCPayServer.JsonConverters; using BTCPayServer.JsonConverters;
using BTCPayServer.Lightning;
using NBitcoin; using NBitcoin;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -15,5 +16,8 @@ namespace BTCPayServer.Client.Models
[JsonConverter(typeof(MoneyJsonConverter))] [JsonConverter(typeof(MoneyJsonConverter))]
public Money MaxFeeFlat { get; set; } public Money MaxFeeFlat { get; set; }
[JsonConverter(typeof(LightMoneyJsonConverter))]
public LightMoney Amount { get; set; }
} }
} }

View file

@ -1518,11 +1518,9 @@ namespace BTCPayServer.Tests
var lnurlResponse2 = await fetchedReuqest.SendRequest(new LightMoney(0.000002m, LightMoneyUnit.BTC), var lnurlResponse2 = await fetchedReuqest.SendRequest(new LightMoney(0.000002m, LightMoneyUnit.BTC),
network, new HttpClient(), comment: "lol2"); network, new HttpClient(), comment: "lol2");
Assert.Equal(new LightMoney(0.000002m, LightMoneyUnit.BTC), lnurlResponse2.GetPaymentRequest(network).MinimumAmount); Assert.Equal(new LightMoney(0.000002m, LightMoneyUnit.BTC), lnurlResponse2.GetPaymentRequest(network).MinimumAmount);
await Assert.ThrowsAnyAsync<LightningRPCException>(async () => // Initial bolt was cancelled
{ var res = await s.Server.CustomerLightningD.Pay(lnurlResponse.Pr);
// Initial bolt was cancelled Assert.Equal(PayResult.Error, res.Result);
await s.Server.CustomerLightningD.Pay(lnurlResponse.Pr);
});
await s.Server.CustomerLightningD.Pay(lnurlResponse2.Pr); await s.Server.CustomerLightningD.Pay(lnurlResponse2.Pr);
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>

View file

@ -4,7 +4,6 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Lightning; using BTCPayServer.Lightning;
using BTCPayServer.Lightning.CLightning; using BTCPayServer.Lightning.CLightning;
@ -174,11 +173,11 @@ namespace BTCPayServer.Tests
SendLightningPaymentAsync(invoice).GetAwaiter().GetResult(); SendLightningPaymentAsync(invoice).GetAwaiter().GetResult();
} }
public async Task SendLightningPaymentAsync(Invoice invoice) public async Task<PayResponse> 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); bolt11 = bolt11.Replace("lightning:", "", StringComparison.OrdinalIgnoreCase);
await CustomerLightningD.Pay(bolt11); return await CustomerLightningD.Pay(bolt11);
} }
public async Task<T> WaitForEvent<T>(Func<Task> action, Func<T, bool> correctEvent = null) public async Task<T> WaitForEvent<T>(Func<Task> action, Func<T, bool> correctEvent = null)

View file

@ -5,8 +5,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
@ -17,7 +15,6 @@ using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models; using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Configuration;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
@ -26,7 +23,6 @@ using BTCPayServer.Fido2.Models;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Hosting; using BTCPayServer.Hosting;
using BTCPayServer.Lightning; using BTCPayServer.Lightning;
using BTCPayServer.Lightning.CLightning;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.AccountViewModels; using BTCPayServer.Models.AccountViewModels;
using BTCPayServer.Models.AppViewModels; using BTCPayServer.Models.AppViewModels;
@ -39,33 +35,26 @@ using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin; using BTCPayServer.Payments.Bitcoin;
using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.Lightning;
using BTCPayServer.Payments.PayJoin.Sender; using BTCPayServer.Payments.PayJoin.Sender;
using BTCPayServer.Rating;
using BTCPayServer.Security.Bitpay; using BTCPayServer.Security.Bitpay;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Labels;
using BTCPayServer.Services.Mails; using BTCPayServer.Services.Mails;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;
using BTCPayServer.Storage.Models; using BTCPayServer.Storage.Models;
using BTCPayServer.Storage.Services.Providers.FileSystemStorage.Configuration; using BTCPayServer.Storage.Services.Providers.FileSystemStorage.Configuration;
using BTCPayServer.Storage.ViewModels; using BTCPayServer.Storage.ViewModels;
using BTCPayServer.Tests.Logging;
using BTCPayServer.Validation;
using ExchangeSharp; using ExchangeSharp;
using Fido2NetLib; using Fido2NetLib;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NBitcoin; using NBitcoin;
using NBitcoin.DataEncoders; using NBitcoin.DataEncoders;
using NBitcoin.Payment; using NBitcoin.Payment;
using NBitcoin.Socks;
using NBitpayClient; using NBitpayClient;
using NBXplorer; using NBXplorer;
using NBXplorer.DerivationStrategy;
using NBXplorer.Models; using NBXplorer.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -390,11 +379,9 @@ namespace BTCPayServer.Tests
Assert.Equal(InvoiceExceptionStatus.None, fetchedInvoice.ExceptionStatus); Assert.Equal(InvoiceExceptionStatus.None, fetchedInvoice.ExceptionStatus);
//BTCPay will attempt to cancel previous bolt11 invoices so that there are less weird edge case scenarios //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 "); TestLogs.LogInformation($"Attempting to pay invoice {invoice.Id} original full amount bolt11 invoice");
await Assert.ThrowsAsync<LightningRPCException>(async () => var res = await tester.SendLightningPaymentAsync(invoice);
{ Assert.Equal(PayResult.Error, res.Result);
await tester.SendLightningPaymentAsync(invoice);
});
//NOTE: Eclair does not support cancelling invoice so the below test case would make sense for it //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 "); // TestLogs.LogInformation($"Paying invoice {invoice.Id} original full amount bolt11 invoice ");

View file

@ -48,7 +48,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BIP78.Sender" Version="0.2.2" /> <PackageReference Include="BIP78.Sender" Version="0.2.2" />
<PackageReference Include="BTCPayServer.Hwi" Version="2.0.2" /> <PackageReference Include="BTCPayServer.Hwi" Version="2.0.2" />
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.3.6" /> <PackageReference Include="BTCPayServer.Lightning.All" Version="1.3.7" />
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" /> <PackageReference Include="BuildBundlerMinifier" Version="3.2.449" />
<PackageReference Include="BundlerMinifier.Core" Version="3.2.435" /> <PackageReference Include="BundlerMinifier.Core" Version="3.2.435" />
<PackageReference Include="BundlerMinifier.TagHelpers" Version="3.2.435" /> <PackageReference Include="BundlerMinifier.TagHelpers" Version="3.2.435" />

View file

@ -6,10 +6,8 @@ using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.HostedServices;
using BTCPayServer.Lightning; using BTCPayServer.Lightning;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
@ -187,8 +185,8 @@ namespace BTCPayServer.Controllers.Greenfield
return this.CreateValidationError(ModelState); return this.CreateValidationError(ModelState);
} }
var param = lightningInvoice?.MaxFeeFlat != null || lightningInvoice?.MaxFeePercent != null var param = lightningInvoice?.MaxFeeFlat != null || lightningInvoice?.MaxFeePercent != null || lightningInvoice?.Amount != null
? new PayInvoiceParams { MaxFeePercent = lightningInvoice.MaxFeePercent, MaxFeeFlat = lightningInvoice.MaxFeeFlat } ? new PayInvoiceParams { MaxFeePercent = lightningInvoice.MaxFeePercent, MaxFeeFlat = lightningInvoice.MaxFeeFlat, Amount = lightningInvoice.Amount }
: null; : null;
var result = await lightningClient.Pay(lightningInvoice.BOLT11, param, cancellationToken); var result = await lightningClient.Pay(lightningInvoice.BOLT11, param, cancellationToken);

View file

@ -204,6 +204,11 @@
"type": "string", "type": "string",
"description": "The BOLT11 of the invoice to pay" "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": { "maxFeePercent": {
"type": "string", "type": "string",
"format": "float", "format": "float",