diff --git a/BTCPayServer.Client/BTCPayServer.Client.csproj b/BTCPayServer.Client/BTCPayServer.Client.csproj
index c0b6b4e20..694d2fc83 100644
--- a/BTCPayServer.Client/BTCPayServer.Client.csproj
+++ b/BTCPayServer.Client/BTCPayServer.Client.csproj
@@ -28,7 +28,7 @@
-
+
diff --git a/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs b/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs
index 6d7e6a404..6e94a25a5 100644
--- a/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs
+++ b/BTCPayServer.Client/Models/PayLightningInvoiceRequest.cs
@@ -1,3 +1,4 @@
+using System;
using BTCPayServer.Client.JsonConverters;
using BTCPayServer.JsonConverters;
using BTCPayServer.Lightning;
@@ -19,5 +20,8 @@ namespace BTCPayServer.Client.Models
[JsonConverter(typeof(LightMoneyJsonConverter))]
public LightMoney Amount { get; set; }
+
+ [JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
+ public TimeSpan? SendTimeout { get; set; }
}
}
diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj
index 4d36db9b7..8e4c644b1 100644
--- a/BTCPayServer/BTCPayServer.csproj
+++ b/BTCPayServer/BTCPayServer.csproj
@@ -41,7 +41,7 @@
-
+
diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs
index d2f705ca4..0291b9254 100644
--- a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs
+++ b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs
@@ -2,7 +2,6 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
@@ -222,16 +221,26 @@ namespace BTCPayServer.Controllers.Greenfield
return this.CreateValidationError(ModelState);
}
- var param = lightningInvoice.MaxFeeFlat != null || lightningInvoice.MaxFeePercent != null || lightningInvoice.Amount != null
- ? new PayInvoiceParams { MaxFeePercent = lightningInvoice.MaxFeePercent, MaxFeeFlat = lightningInvoice.MaxFeeFlat, Amount = lightningInvoice.Amount }
+ var param = lightningInvoice.MaxFeeFlat != null || lightningInvoice.MaxFeePercent != null
+ || lightningInvoice.Amount != null || lightningInvoice.SendTimeout != null
+ ? new PayInvoiceParams
+ {
+ MaxFeePercent = lightningInvoice.MaxFeePercent,
+ MaxFeeFlat = lightningInvoice.MaxFeeFlat,
+ Amount = lightningInvoice.Amount,
+ SendTimeout = lightningInvoice.SendTimeout
+ }
: null;
var result = await lightningClient.Pay(lightningInvoice.BOLT11, param, cancellationToken);
- if (result.Result == PayResult.Ok && bolt11?.PaymentHash is not null)
+ if (result.Result is PayResult.Ok or PayResult.Unknown && bolt11?.PaymentHash is not null)
{
+ // get a new instance of the LN client, because the old one might have disposed its HTTPClient
+ lightningClient = await GetLightningClient(cryptoCode, true);
+
var paymentHash = bolt11.PaymentHash.ToString();
var payment = await lightningClient.GetPayment(paymentHash, cancellationToken);
- return Ok(new LightningPaymentData
+ var data = new LightningPaymentData
{
Id = payment.Id,
PaymentHash = paymentHash,
@@ -241,19 +250,25 @@ namespace BTCPayServer.Controllers.Greenfield
CreatedAt = payment.CreatedAt,
TotalAmount = payment.AmountSent,
FeeAmount = payment.Fee,
- });
+ };
+ return result.Result is PayResult.Ok ? Ok(data) : Accepted(data);
}
return result.Result switch
{
PayResult.CouldNotFindRoute => this.CreateAPIError("could-not-find-route", "Impossible to find a route to the peer"),
PayResult.Error => this.CreateAPIError("generic-error", result.ErrorDetail),
+ PayResult.Unknown => Accepted(new LightningPaymentData
+ {
+ Status = LightningPaymentStatus.Unknown
+ }),
PayResult.Ok => Ok(new LightningPaymentData
{
+ Status = LightningPaymentStatus.Complete,
TotalAmount = result.Details?.TotalAmount,
FeeAmount = result.Details?.FeeAmount
}),
- _ => throw new NotSupportedException("Unsupported Payresult")
+ _ => throw new NotSupportedException("Unsupported PayResult")
};
}
diff --git a/BTCPayServer/Data/Payouts/LightningLike/UILightningLikePayoutController.cs b/BTCPayServer/Data/Payouts/LightningLike/UILightningLikePayoutController.cs
index 4f5029dc8..63e031c80 100644
--- a/BTCPayServer/Data/Payouts/LightningLike/UILightningLikePayoutController.cs
+++ b/BTCPayServer/Data/Payouts/LightningLike/UILightningLikePayoutController.cs
@@ -281,6 +281,8 @@ namespace BTCPayServer.Data.Payouts.LightningLike
var proofBlob = new PayoutLightningBlob() {PaymentHash = bolt11PaymentRequest.PaymentHash.ToString()};
try
{
+ // TODO: Incorporate the changes from this PR here:
+ // https://github.com/btcpayserver/BTCPayServer.Lightning/pull/106
using var cts = new CancellationTokenSource(SendTimeout);
var result = await lightningClient.Pay(bolt11PaymentRequest.ToString(),
new PayInvoiceParams()
diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.json
index 1932a3a9c..d0fff2450 100644
--- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.json
+++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.json
@@ -100,7 +100,6 @@
},
"TimeSpanSeconds": {
"allOf": [ { "$ref": "#/components/schemas/TimeSpan" } ],
-
"format": "seconds",
"description": "A span of times in seconds"
},
diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json
index 78f41eb42..7418d99fb 100644
--- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json
+++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.common.json
@@ -323,6 +323,17 @@
"nullable": true,
"description": "The fee limit expressed as a fixed amount in satoshi",
"example": "21"
+ },
+ "sendTimeout": {
+ "nullable": true,
+ "example": 30,
+ "default": 30,
+ "description": "The number of seconds after which the payment times out",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/TimeSpanSeconds"
+ }
+ ]
}
}
},
diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json
index 22f1c28f1..22eb5884a 100644
--- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json
+++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json
@@ -465,7 +465,7 @@
"example": "BTC"
}
],
- "description": "Pay a lightning invoice.",
+ "description": "Pay a lightning invoice. In case the payment response times out, the status will be reported as pending and the final status can be resolved using the [Get payment](#operation/InternalLightningNodeApi_GetPayment) endpoint. The default wait time for payment responses is 30 seconds — it might take longer if multiple routes are tried or a hold invoice is getting paid.",
"operationId": "InternalLightningNodeApi_PayInvoice",
"responses": {
"200": {
@@ -478,6 +478,16 @@
}
}
},
+ "202": {
+ "description": "Payment initiated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LightningPaymentData"
+ }
+ }
+ }
+ },
"422": {
"description": "Unable to validate the request",
"content": {
diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json
index 9de0f1903..f1c5744d3 100644
--- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json
+++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json
@@ -548,7 +548,7 @@
}
}
],
- "description": "Pay a lightning invoice.",
+ "description": "Pay a lightning invoice. In case the payment response times out, the status will be reported as pending and the final status can be resolved using the [Get payment](#operation/StoreLightningNodeApi_GetPayment) endpoint. The default wait time for payment responses is 30 seconds — it might take longer if multiple routes are tried or a hold invoice is getting paid.",
"operationId": "StoreLightningNodeApi_PayInvoice",
"responses": {
"200": {
@@ -561,6 +561,16 @@
}
}
},
+ "202": {
+ "description": "Payment initiated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LightningPaymentData"
+ }
+ }
+ }
+ },
"422": {
"description": "Unable to validate the request",
"content": {