diff --git a/BTCPayServer.Client/BTCPayServerClient.Lightning.Internal.cs b/BTCPayServer.Client/BTCPayServerClient.Lightning.Internal.cs index 7aaf5f0a9..7d777521e 100644 --- a/BTCPayServer.Client/BTCPayServerClient.Lightning.Internal.cs +++ b/BTCPayServer.Client/BTCPayServerClient.Lightning.Internal.cs @@ -113,6 +113,24 @@ namespace BTCPayServer.Client CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/invoices", queryPayload), token); return await HandleResponse(response); } + + public virtual async Task GetLightningPayments(string cryptoCode, + bool? includePending = null, long? offsetIndex = null, CancellationToken token = default) + { + var queryPayload = new Dictionary(); + if (includePending is bool v) + { + queryPayload.Add("includePending", v.ToString()); + } + if (offsetIndex is > 0) + { + queryPayload.Add("offsetIndex", offsetIndex); + } + + var response = await _httpClient.SendAsync( + CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/payments", queryPayload), token); + return await HandleResponse(response); + } public virtual async Task CreateLightningInvoice(string cryptoCode, CreateLightningInvoiceRequest request, CancellationToken token = default) diff --git a/BTCPayServer.Client/BTCPayServerClient.Lightning.Store.cs b/BTCPayServer.Client/BTCPayServerClient.Lightning.Store.cs index 298f22cbc..e2dc8bf6f 100644 --- a/BTCPayServer.Client/BTCPayServerClient.Lightning.Store.cs +++ b/BTCPayServer.Client/BTCPayServerClient.Lightning.Store.cs @@ -115,6 +115,24 @@ namespace BTCPayServer.Client CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices", queryPayload), token); return await HandleResponse(response); } + + public virtual async Task GetLightningPayments(string storeId, string cryptoCode, + bool? includePending = null, long? offsetIndex = null, CancellationToken token = default) + { + var queryPayload = new Dictionary(); + if (includePending is bool v) + { + queryPayload.Add("includePending", v.ToString()); + } + if (offsetIndex is > 0) + { + queryPayload.Add("offsetIndex", offsetIndex); + } + + var response = await _httpClient.SendAsync( + CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/payments", queryPayload), token); + return await HandleResponse(response); + } public virtual async Task CreateLightningInvoice(string storeId, string cryptoCode, CreateLightningInvoiceRequest request, CancellationToken token = default) diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 2d361b53e..2637e4e21 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -2259,7 +2259,13 @@ namespace BTCPayServer.Tests // Amount received might be bigger because of internal implementation shit from lightning Assert.True(LightMoney.Satoshis(1000) <= invoice.AmountReceived); + + // check payments list for store node + var payments = await client.GetLightningPayments(user.StoreId, "BTC"); + Assert.NotEmpty(payments); + Assert.Contains(payments, i => i.BOLT11 == merchantInvoice.BOLT11); + // Node info info = await client.GetLightningNodeInfo(user.StoreId, "BTC"); Assert.Single(info.NodeURIs); Assert.NotEqual(0, info.BlockHeight); diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Internal.cs b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Internal.cs index 370f566d3..70fdcd9ff 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Internal.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Internal.cs @@ -125,6 +125,14 @@ namespace BTCPayServer.Controllers.Greenfield return base.CreateInvoice(cryptoCode, request, cancellationToken); } + [Authorize(Policy = Policies.CanUseInternalLightningNode, + AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpGet("~/api/v1/server/lightning/{cryptoCode}/payments")] + public override Task GetPayments(string cryptoCode, [FromQuery] bool? includePending, [FromQuery] long? offsetIndex, CancellationToken cancellationToken = default) + { + return base.GetPayments(cryptoCode, includePending, offsetIndex, cancellationToken); + } + protected override async Task GetLightningClient(string cryptoCode, bool doingAdminThings) { var network = _btcPayNetworkProvider.GetNetwork(cryptoCode); diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Store.cs b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Store.cs index 9ebc498d3..73e02e45b 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Store.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.Store.cs @@ -127,6 +127,14 @@ namespace BTCPayServer.Controllers.Greenfield return base.CreateInvoice(cryptoCode, request, cancellationToken); } + [Authorize(Policy = Policies.CanUseLightningNodeInStore, + AuthenticationSchemes = AuthenticationSchemes.Greenfield)] + [HttpGet("~/api/v1/stores/{storeId}/lightning/{cryptoCode}/payments")] + public override Task GetPayments(string cryptoCode, [FromQuery] bool? includePending, [FromQuery] long? offsetIndex, CancellationToken cancellationToken = default) + { + return base.GetPayments(cryptoCode, includePending, offsetIndex, cancellationToken); + } + protected override Task GetLightningClient(string cryptoCode, bool doingAdminThings) { diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs index e485bc5d2..659daa940 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldLightningNodeApiController.cs @@ -290,6 +290,14 @@ namespace BTCPayServer.Controllers.Greenfield return Ok(invoices.Select(ToModel)); } + public virtual async Task GetPayments(string cryptoCode, [FromQuery] bool? includePending, [FromQuery] long? offsetIndex, CancellationToken cancellationToken = default) + { + var lightningClient = await GetLightningClient(cryptoCode, false); + var param = new ListPaymentsParams { IncludePending = includePending, OffsetIndex = offsetIndex }; + var payments = await lightningClient.ListPayments(param, cancellationToken); + return Ok(payments.Select(ToModel)); + } + public virtual async Task CreateInvoice(string cryptoCode, CreateLightningInvoiceRequest request, CancellationToken cancellationToken = default) { var lightningClient = await GetLightningClient(cryptoCode, false); diff --git a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs b/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs index ae48cfdef..d6cee62f3 100644 --- a/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs +++ b/BTCPayServer/Controllers/GreenField/LocalBTCPayServerClient.cs @@ -436,6 +436,13 @@ namespace BTCPayServer.Controllers.Greenfield await GetController().GetInvoices(cryptoCode, pendingOnly, offsetIndex, token)); } + public override async Task GetLightningPayments(string storeId, string cryptoCode, + bool? includePending = null, long? offsetIndex = null, CancellationToken token = default) + { + return GetFromActionResult( + await GetController().GetPayments(cryptoCode, includePending, offsetIndex, token)); + } + public override async Task CreateLightningInvoice(string storeId, string cryptoCode, CreateLightningInvoiceRequest request, CancellationToken token = default) { @@ -504,6 +511,13 @@ namespace BTCPayServer.Controllers.Greenfield await GetController().GetInvoices(cryptoCode, pendingOnly, offsetIndex, token)); } + public override async Task GetLightningPayments(string cryptoCode, + bool? includePending = null, long? offsetIndex = null, CancellationToken token = default) + { + return GetFromActionResult( + await GetController().GetPayments(cryptoCode, includePending, offsetIndex, token)); + } + public override async Task CreateLightningInvoice(string cryptoCode, CreateLightningInvoiceRequest request, CancellationToken token = default) diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json index 15e4781da..4f08d793f 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.internal.json @@ -691,6 +691,96 @@ } ] } + }, + "/api/v1/server/lightning/{cryptoCode}/payments": { + "get": { + "tags": [ + "Lightning (Internal Node)" + ], + "summary": "Get payments", + "parameters": [ + { + "name": "cryptoCode", + "in": "path", + "required": true, + "description": "The cryptoCode of the lightning-node to query", + "schema": { + "type": "string" + }, + "example": "BTC" + }, + { + "name": "includePending", + "in": "query", + "required": false, + "description": "Also include pending payments", + "schema": { + "type": "boolean", + "nullable": true, + "default": false + } + }, + { + "name": "offsetIndex", + "in": "query", + "required": false, + "description": "The index of a payment that will be used as the start of the list", + "schema": { + "type": "number", + "nullable": true, + "default": 0 + } + } + ], + "description": "View information about the lightning payments", + "operationId": "InternalLightningNodeApi_GetPayments", + "responses": { + "200": { + "description": "Lightning payment data", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LightningPaymentData" + } + } + } + } + }, + "401": { + "description": "Missing authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "503": { + "description": "Unable to access the lightning node" + }, + "default": { + "description": "Unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "API_Key": [ + "btcpay.server.canuseinternallightningnode" + ], + "Basic": [] + } + ] + } } }, "tags": [ diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json index f194ce373..9bdf8234d 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.lightning.store.json @@ -791,6 +791,105 @@ } ] } + }, + "/api/v1/stores/{storeId}/lightning/{cryptoCode}/payments": { + "get": { + "tags": [ + "Lightning (Store)" + ], + "summary": "Get payments", + "parameters": [ + { + "name": "cryptoCode", + "in": "path", + "required": true, + "description": "The cryptoCode of the lightning-node to query", + "schema": { + "type": "string" + }, + "example": "BTC" + }, + { + "name": "storeId", + "in": "path", + "required": true, + "description": "The store id with the lightning-node configuration to query", + "schema": { + "type": "string" + } + }, + { + "name": "includePending", + "in": "query", + "required": false, + "description": "Also include pending payments", + "schema": { + "type": "boolean", + "nullable": true, + "default": false + } + }, + { + "name": "offsetIndex", + "in": "query", + "required": false, + "description": "The index of an invoice that will be used as the start of the list", + "schema": { + "type": "number", + "nullable": true, + "default": 0 + } + } + ], + "description": "View information about the lightning payments", + "operationId": "StoreLightningNodeApi_GetPayments", + "responses": { + "200": { + "description": "Lightning payment data", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LightningPaymentData" + } + } + } + } + }, + "401": { + "description": "Missing authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "503": { + "description": "Unable to access the lightning node" + }, + "default": { + "description": "Unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "API_Key": [ + "btcpay.store.cancreatelightninginvoice" + ], + "Basic": [] + } + ] + } } }, "tags": [