mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
Lightning payment info and fee handling (#3454)
* Lightning payment info and fee handling Builds on the additions in btcpayserver/BTCPayServer.Lightning#59 and btcpayserver/BTCPayServer.Lightning#61. Adds payment information (total amount and fees) to the API response and allows to set an optional maximum fee percentage when paying. * Add max fee flat
This commit is contained in:
@@ -28,8 +28,8 @@
|
|||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="NBitcoin" Version="6.0.19" />
|
<PackageReference Include="NBitcoin" Version="7.0.1" />
|
||||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.3.0" />
|
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.3.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ namespace BTCPayServer.Client
|
|||||||
return await HandleResponse<string>(response);
|
return await HandleResponse<string>(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual async Task<LightningPaymentData> PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
|
||||||
public virtual async Task PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
|
|
||||||
CancellationToken token = default)
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (request == null)
|
if (request == null)
|
||||||
@@ -63,7 +62,7 @@ namespace BTCPayServer.Client
|
|||||||
var response = await _httpClient.SendAsync(
|
var response = await _httpClient.SendAsync(
|
||||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/invoices/pay", bodyPayload: request,
|
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/invoices/pay", bodyPayload: request,
|
||||||
method: HttpMethod.Post), token);
|
method: HttpMethod.Post), token);
|
||||||
await HandleResponse(response);
|
return await HandleResponse<LightningPaymentData>(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode,
|
public virtual async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode,
|
||||||
|
|||||||
15
BTCPayServer.Client/Models/LightningPaymentData.cs
Normal file
15
BTCPayServer.Client/Models/LightningPaymentData.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using BTCPayServer.Client.JsonConverters;
|
||||||
|
using BTCPayServer.Lightning;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Client.Models
|
||||||
|
{
|
||||||
|
public class LightningPaymentData
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||||
|
public LightMoney TotalAmount { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(LightMoneyJsonConverter))]
|
||||||
|
public LightMoney FeeAmount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,20 @@
|
|||||||
|
#nullable enable
|
||||||
|
using BTCPayServer.Client.JsonConverters;
|
||||||
|
using BTCPayServer.JsonConverters;
|
||||||
|
using NBitcoin;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace BTCPayServer.Client.Models
|
namespace BTCPayServer.Client.Models
|
||||||
{
|
{
|
||||||
public class PayLightningInvoiceRequest
|
public class PayLightningInvoiceRequest
|
||||||
{
|
{
|
||||||
[Newtonsoft.Json.JsonProperty("BOLT11")]
|
[JsonProperty("BOLT11")]
|
||||||
public string BOLT11 { get; set; }
|
public string BOLT11 { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
|
||||||
|
public float? MaxFeePercent { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(MoneyJsonConverter))]
|
||||||
|
public Money? MaxFeeFlat { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
|
||||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
||||||
<PackageReference Include="NBitcoin" Version="6.0.19" />
|
<PackageReference Include="NBitcoin" Version="7.0.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.6.3" />
|
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.6.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -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.0" />
|
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.3.2" />
|
||||||
<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" />
|
||||||
|
|||||||
@@ -178,19 +178,23 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
{
|
{
|
||||||
return this.CreateValidationError(ModelState);
|
return this.CreateValidationError(ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await lightningClient.Pay(lightningInvoice.BOLT11);
|
var param = lightningInvoice?.MaxFeeFlat != null || lightningInvoice?.MaxFeePercent != null
|
||||||
switch (result.Result)
|
? new PayInvoiceParams { MaxFeePercent = lightningInvoice.MaxFeePercent, MaxFeeFlat = lightningInvoice.MaxFeeFlat }
|
||||||
|
: null;
|
||||||
|
var result = await lightningClient.Pay(lightningInvoice.BOLT11, param);
|
||||||
|
|
||||||
|
return result.Result switch
|
||||||
{
|
{
|
||||||
case PayResult.CouldNotFindRoute:
|
PayResult.CouldNotFindRoute => this.CreateAPIError("could-not-find-route", "Impossible to find a route to the peer"),
|
||||||
return this.CreateAPIError("could-not-find-route", "Impossible to find a route to the peer");
|
PayResult.Error => this.CreateAPIError("generic-error", result.ErrorDetail),
|
||||||
case PayResult.Error:
|
PayResult.Ok => Ok(new LightningPaymentData
|
||||||
return this.CreateAPIError("generic-error", result.ErrorDetail);
|
{
|
||||||
case PayResult.Ok:
|
TotalAmount = result.Details?.TotalAmount,
|
||||||
return Ok();
|
FeeAmount = result.Details?.FeeAmount
|
||||||
default:
|
}),
|
||||||
throw new NotSupportedException("Unsupported Payresult");
|
_ => throw new NotSupportedException("Unsupported Payresult")
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<IActionResult> GetInvoice(string cryptoCode, string id)
|
public virtual async Task<IActionResult> GetInvoice(string cryptoCode, string id)
|
||||||
@@ -253,7 +257,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
private LightningInvoiceData ToModel(LightningInvoice invoice)
|
private LightningInvoiceData ToModel(LightningInvoice invoice)
|
||||||
{
|
{
|
||||||
return new LightningInvoiceData()
|
return new LightningInvoiceData
|
||||||
{
|
{
|
||||||
Amount = invoice.Amount,
|
Amount = invoice.Amount,
|
||||||
Id = invoice.Id,
|
Id = invoice.Id,
|
||||||
|
|||||||
@@ -497,10 +497,11 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
await _lightningNodeApiController.GetDepositAddress(cryptoCode));
|
await _lightningNodeApiController.GetDepositAddress(cryptoCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
|
public override async Task<LightningPaymentData> PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
|
||||||
CancellationToken token = default)
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
HandleActionResult(await _lightningNodeApiController.PayInvoice(cryptoCode, request));
|
return GetFromActionResult<LightningPaymentData>(
|
||||||
|
await _lightningNodeApiController.PayInvoice(cryptoCode, request));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode, string invoiceId,
|
public override async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode, string invoiceId,
|
||||||
@@ -518,7 +519,6 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
await _lightningNodeApiController.CreateInvoice(cryptoCode, request));
|
await _lightningNodeApiController.CreateInvoice(cryptoCode, request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private T GetFromActionResult<T>(IActionResult result)
|
private T GetFromActionResult<T>(IActionResult result)
|
||||||
{
|
{
|
||||||
HandleActionResult(result);
|
HandleActionResult(result);
|
||||||
|
|||||||
@@ -70,6 +70,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"LightningPaymentData": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"totalAmount": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The total amount (including fees) in millisatoshi"
|
||||||
|
},
|
||||||
|
"feeAmount": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The total fees in millisatoshi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"LightningInvoiceData": {
|
"LightningInvoiceData": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -141,6 +155,19 @@
|
|||||||
"BOLT11": {
|
"BOLT11": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The BOLT11 of the invoice to pay"
|
"description": "The BOLT11 of the invoice to pay"
|
||||||
|
},
|
||||||
|
"maxFeePercent": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "float",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "The fee limit expressed as a percentage of the payment amount",
|
||||||
|
"example": "6.15"
|
||||||
|
},
|
||||||
|
"maxFeeFlat": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "The fee limit expressed as a fixed amount in satoshi",
|
||||||
|
"example": "21"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -361,7 +361,14 @@
|
|||||||
"operationId": "InternalLightningNodeApi_PayInvoice",
|
"operationId": "InternalLightningNodeApi_PayInvoice",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Successfully paid"
|
"description": "Successfully paid",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/LightningPaymentData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"422": {
|
"422": {
|
||||||
"description": "Unable to validate the request",
|
"description": "Unable to validate the request",
|
||||||
|
|||||||
@@ -428,7 +428,14 @@
|
|||||||
"operationId": "StoreLightningNodeApi_PayInvoice",
|
"operationId": "StoreLightningNodeApi_PayInvoice",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Successfully paid"
|
"description": "Successfully paid",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/LightningPaymentData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"422": {
|
"422": {
|
||||||
"description": "Unable to validate the request",
|
"description": "Unable to validate the request",
|
||||||
|
|||||||
Reference in New Issue
Block a user