diff --git a/.gitignore b/.gitignore index b8aa954..295fd14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,7 @@ **/bin/**/* **/obj -**/.idea -*//Plugins/packed +.idea +Plugins/packed .vs/ /BTCPayServerPlugins.sln.DotSettings.user -*/documentation/ -**/build.sh -*/build-and-test.sh +documentation/ diff --git a/dist/BTCPayServer.Plugins.Breez/1.1.0.0/BTCPayServer.Plugins.Breez.btcpay b/dist/BTCPayServer.Plugins.Breez/1.1.0.0/BTCPayServer.Plugins.Breez.btcpay deleted file mode 100644 index 1f1d9e8..0000000 Binary files a/dist/BTCPayServer.Plugins.Breez/1.1.0.0/BTCPayServer.Plugins.Breez.btcpay and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.Breez/1.1.0.0/BTCPayServer.Plugins.Breez.btcpay.json b/dist/BTCPayServer.Plugins.Breez/1.1.0.0/BTCPayServer.Plugins.Breez.btcpay.json deleted file mode 100644 index 7413f94..0000000 --- a/dist/BTCPayServer.Plugins.Breez/1.1.0.0/BTCPayServer.Plugins.Breez.btcpay.json +++ /dev/null @@ -1 +0,0 @@ -{"Identifier":"BTCPayServer.Plugins.Breez","Name":"Breez Spark Lightning Plugin","Version":"1.1.0.0","Description":"Nodeless Lightning payments powered by Breez Spark SDK","SystemPlugin":false,"Dependencies":[{"Identifier":"BTCPayServer","Condition":"\u003E=2.2.0"}]} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.Breez/1.1.0.0/SHA256SUMS b/dist/BTCPayServer.Plugins.Breez/1.1.0.0/SHA256SUMS deleted file mode 100644 index d949820..0000000 --- a/dist/BTCPayServer.Plugins.Breez/1.1.0.0/SHA256SUMS +++ /dev/null @@ -1,2 +0,0 @@ -30a4ce17e09c22d168db00ba618f9c76d015a248fa88793f5d333768fe346d95 BTCPayServer.Plugins.Breez.btcpay.json -a8062f16f45ba6d5e9de9cfdfdb34eb7e542d4f4d908aa77f7cdc596035c13ed BTCPayServer.Plugins.Breez.btcpay diff --git a/dist/BTCPayServer.Plugins.Breez/1.1.0.0/SHA256SUMS.asc b/dist/BTCPayServer.Plugins.Breez/1.1.0.0/SHA256SUMS.asc deleted file mode 100644 index e69de29..0000000 diff --git a/dist/BTCPayServer.Plugins.BreezSpark.json b/dist/BTCPayServer.Plugins.BreezSpark.json deleted file mode 100644 index e79ffce..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Identifier": "BTCPayServer.Plugins.BreezSpark", - "Name": "BreezSpark Lightning Plugin", - "Version": "1.1.0", - "Description": "Nodeless Lightning payments powered by Breez Spark SDK", - "Author": "Aljaz Ceru", - "AuthorLink": "https://github.com/aljazceru", - "SystemPlugin": false, - "Dependencies": [ - { - "Identifier": "BTCPayServer", - "Condition": ">=2.2.0" - } - ] -} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark.v3.btcpay b/dist/BTCPayServer.Plugins.BreezSpark.v3.btcpay deleted file mode 100644 index 6e90734..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark.v3.btcpay and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.csproj b/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.csproj deleted file mode 100644 index 1e756e6..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.csproj +++ /dev/null @@ -1,47 +0,0 @@ - - - - net8.0 - latest - enable - true - $(NoWarn);CS1591 - - - - - BreezSpark Lightning Plugin - Nodeless Lightning payments powered by Breez Spark SDK - 1.1.0 - Aljaz Ceru - Aljaz Ceru - BTCPayServer.Plugins.BreezSpark - BTCPayServer.Plugins.BreezSpark -true - - - - true - false - true - - - - - - StaticWebAssetsEnabled=false - false - runtime;native;build;buildTransitive;contentFiles - - - - - - - - - - - - - diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.deps.json b/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.deps.json deleted file mode 100644 index 3b924af..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.deps.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v8.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v8.0": { - "BTCPayServer.Plugins.BreezSpark/1.1.0": { - "dependencies": { - "Breez.Sdk.Spark": "0.4.1" - }, - "runtime": { - "BTCPayServer.Plugins.BreezSpark.dll": {} - } - }, - "Breez.Sdk.Spark/0.4.1": { - "runtime": { - "lib/net8.0/Breez.Sdk.Spark.dll": { - "assemblyVersion": "0.4.1.0", - "fileVersion": "0.4.1.0" - } - }, - "runtimeTargets": { - "runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so": { - "rid": "linux-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib": { - "rid": "osx-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib": { - "rid": "osx-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x64/native/breez_sdk_spark_bindings.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x86/native/breez_sdk_spark_bindings.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "0.0.0.0" - } - } - } - } - }, - "libraries": { - "BTCPayServer.Plugins.BreezSpark/1.1.0": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Breez.Sdk.Spark/0.4.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-/5iC7V3PK0q5og4h5qnSf5xepfvcXSEeV5WJDIAlOGd7WUtMZdNQ0n6yDcgd1Rv5qcxPQsDGQN3IVQZbP0UE1w==", - "path": "breez.sdk.spark/0.4.1", - "hashPath": "breez.sdk.spark.0.4.1.nupkg.sha512" - } - } -} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.dll b/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.dll deleted file mode 100644 index 79beade..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.dll and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.pdb b/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.pdb deleted file mode 100644 index 89f1b9b..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.pdb and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.staticwebassets.endpoints.json b/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.staticwebassets.endpoints.json deleted file mode 100644 index 21da96b..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.staticwebassets.endpoints.json +++ /dev/null @@ -1 +0,0 @@ -{"Version":1,"ManifestType":"Publish","Endpoints":[]} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.xml b/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.xml deleted file mode 100644 index 25320e3..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - BTCPayServer.Plugins.BreezSpark - - - - diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Breez.Sdk.Spark.dll b/dist/BTCPayServer.Plugins.BreezSpark/Breez.Sdk.Spark.dll deleted file mode 100755 index 7db16f5..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/Breez.Sdk.Spark.dll and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkController.cs b/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkController.cs deleted file mode 100644 index 56dfbc6..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkController.cs +++ /dev/null @@ -1,537 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Numerics; -using System.Text.Json; -using System.Threading.Tasks; -using Breez.Sdk.Spark; -using BTCPayServer.Abstractions.Constants; -using BTCPayServer.Client; -using BTCPayServer.Data; -using BTCPayServer.Lightning; -using BTCPayServer.Models; -using BTCPayServer.Payments; -using BTCPayServer.Payments.Lightning; -using BTCPayServer.Services.Invoices; -using BTCPayServer.Services.Stores; -using BTCPayServer.Services.Wallets; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using NBitcoin; -using NBitcoin.DataEncoders; - -namespace BTCPayServer.Plugins.BreezSpark; - -[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)] -[Route("plugins/{storeId}/BreezSpark")] -public class BreezSparkController : Controller -{ - private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary; - private readonly BTCPayNetworkProvider _btcPayNetworkProvider; - private readonly BreezSparkService _breezService; - private readonly BTCPayWalletProvider _btcWalletProvider; - private readonly StoreRepository _storeRepository; - - public BreezSparkController( - PaymentMethodHandlerDictionary paymentMethodHandlerDictionary, - BTCPayNetworkProvider btcPayNetworkProvider, - BreezSparkService breezService, - BTCPayWalletProvider btcWalletProvider, StoreRepository storeRepository) - { - _paymentMethodHandlerDictionary = paymentMethodHandlerDictionary; - _btcPayNetworkProvider = btcPayNetworkProvider; - _breezService = breezService; - _btcWalletProvider = btcWalletProvider; - _storeRepository = storeRepository; - } - - - [HttpGet("")] - public async Task Index(string storeId) - { - var client = _breezService.GetClient(storeId); - return RedirectToAction(client is null ? nameof(Configure) : nameof(Info), new {storeId}); - } - - [HttpGet("swapin")] - [Authorize(Policy = Policies.CanCreateInvoice, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task SwapIn(string storeId) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - return View((object) storeId); - } - - [HttpGet("info")] - [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Info(string storeId) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - return View((object) storeId); - } - [HttpGet("logs")] - [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Logs(string storeId) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - return View( client.Events); - } - - [HttpPost("sweep")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Sweep(string storeId) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - try - { - // In Spark SDK v0.4.1, check for any unclaimed deposits - var request = new ListUnclaimedDepositsRequest(); - var response = await client.Sdk.ListUnclaimedDeposits(request); - - if (response.deposits.Any()) - { - TempData[WellKnownTempData.SuccessMessage] = $"Found {response.deposits.Count} unclaimed deposits"; - } - else - { - TempData[WellKnownTempData.SuccessMessage] = "No pending deposits to claim"; - } - } - catch (Exception e) - { - TempData[WellKnownTempData.ErrorMessage] = $"error claiming deposits: {e.Message}"; - } - - return View((object) storeId); - } - - [HttpGet("send")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Send(string storeId) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - return View((object) storeId); - } - [Authorize(Policy = Policies.CanCreateInvoice, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - [HttpGet("receive")] - [Authorize(Policy = Policies.CanCreateInvoice, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Receive(string storeId) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - return View((object) storeId); - } - - [HttpPost("receive")] - [Authorize(Policy = Policies.CanCreateInvoice, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Receive(string storeId, long? amount, string description) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - try - { - description ??= "BTCPay Server Invoice"; - - var paymentMethod = new ReceivePaymentMethod.Bolt11Invoice( - description: description, - amountSats: amount != null ? (ulong)amount.Value : null - ); - - var request = new ReceivePaymentRequest(paymentMethod: paymentMethod); - var response = await client.Sdk.ReceivePayment(request: request); - - TempData["bolt11"] = response.paymentRequest; - TempData[WellKnownTempData.SuccessMessage] = "Invoice created successfully!"; - - return RedirectToAction(nameof(Payments), new {storeId}); - } - catch (Exception ex) - { - TempData[WellKnownTempData.ErrorMessage] = $"Error creating invoice: {ex.Message}"; - return View((object) storeId); - } - } - - [HttpPost("prepare-send")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task PrepareSend(string storeId, string address, long? amount) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - try - { - if (string.IsNullOrWhiteSpace(address)) - { - TempData[WellKnownTempData.ErrorMessage] = "Payment destination is required"; - return RedirectToAction(nameof(Send), new {storeId}); - } - - BigInteger? amountSats = null; - if (amount > 0) - { - amountSats = new BigInteger(amount.Value); - } - - var prepareRequest = new PrepareSendPaymentRequest( - paymentRequest: address, - amount: amountSats - ); - - var prepareResponse = await client.Sdk.PrepareSendPayment(prepareRequest); - - if (prepareResponse.paymentMethod is SendPaymentMethod.Bolt11Invoice bolt11Method) - { - var totalFee = bolt11Method.lightningFeeSats + (bolt11Method.sparkTransferFeeSats ?? 0); - var viewModel = new - { - Destination = address, - Amount = amountSats ?? 0, - Fee = totalFee, - PrepareResponseJson = JsonSerializer.Serialize(prepareResponse) - }; - ViewData["PaymentDetails"] = viewModel; - } - else if (prepareResponse.paymentMethod is SendPaymentMethod.BitcoinAddress bitcoinMethod) - { - var fees = bitcoinMethod.feeQuote; - var mediumFee = fees.speedMedium.userFeeSat + fees.speedMedium.l1BroadcastFeeSat; - var viewModel = new - { - Destination = address, - Amount = amountSats ?? 0, - Fee = mediumFee, - PrepareResponseJson = JsonSerializer.Serialize(prepareResponse) - }; - ViewData["PaymentDetails"] = viewModel; - } - else if (prepareResponse.paymentMethod is SendPaymentMethod.SparkAddress sparkMethod) - { - var viewModel = new - { - Destination = address, - Amount = amountSats ?? 0, - Fee = sparkMethod.fee, - PrepareResponseJson = JsonSerializer.Serialize(prepareResponse) - }; - ViewData["PaymentDetails"] = viewModel; - } - } - catch (Exception ex) - { - TempData[WellKnownTempData.ErrorMessage] = $"Error preparing payment: {ex.Message}"; - } - - return View(nameof(Send), storeId); - } - - [HttpPost("confirm-send")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task ConfirmSend(string storeId, string paymentRequest, long amount, string prepareResponseJson) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - try - { - var prepareResponse = JsonSerializer.Deserialize(prepareResponseJson); - if (prepareResponse == null) - { - throw new InvalidOperationException("Invalid payment preparation data"); - } - - SendPaymentOptions? options = prepareResponse.paymentMethod switch - { - SendPaymentMethod.Bolt11Invoice => new SendPaymentOptions.Bolt11Invoice( - preferSpark: false, - completionTimeoutSecs: 60 - ), - SendPaymentMethod.BitcoinAddress => new SendPaymentOptions.BitcoinAddress( - confirmationSpeed: OnchainConfirmationSpeed.Medium - ), - SendPaymentMethod.SparkAddress => null, - _ => throw new NotSupportedException("Unsupported payment method") - }; - - var sendRequest = new SendPaymentRequest( - prepareResponse: prepareResponse, - options: options - ); - - var sendResponse = await client.Sdk.SendPayment(sendRequest); - - TempData[WellKnownTempData.SuccessMessage] = "Payment sent successfully!"; - return RedirectToAction(nameof(Payments), new {storeId}); - } - catch (Exception ex) - { - TempData[WellKnownTempData.ErrorMessage] = $"Error sending payment: {ex.Message}"; - return RedirectToAction(nameof(Send), new {storeId}); - } - } - - - [HttpGet("swapout")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task SwapOut(string storeId) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - return View((object) storeId); - } - - [HttpPost("swapout")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task SwapOut(string storeId, string address, ulong amount, uint satPerByte, - string feesHash) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - try - { - // Use current SDK pattern for onchain payments - var prepareRequest = new PrepareSendPaymentRequest( - paymentRequest: address, - amount: new BigInteger(amount) - ); - - var prepareResponse = await client.Sdk.PrepareSendPayment(prepareRequest); - - if (prepareResponse.paymentMethod is SendPaymentMethod.BitcoinAddress bitcoinMethod) - { - var options = new SendPaymentOptions.BitcoinAddress( - confirmationSpeed: OnchainConfirmationSpeed.Medium - ); - - var sendRequest = new SendPaymentRequest( - prepareResponse: prepareResponse, - options: options - ); - - var sendResponse = await client.Sdk.SendPayment(sendRequest); - - TempData[WellKnownTempData.SuccessMessage] = "Onchain payment initiated successfully!"; - } - else - { - TempData[WellKnownTempData.ErrorMessage] = "Invalid payment method for onchain swap"; - } - } - catch (Exception ex) - { - TempData[WellKnownTempData.ErrorMessage] = $"Error processing swap-out: {ex.Message}"; - } - - return RedirectToAction(nameof(SwapOut), new {storeId}); - } - - [HttpGet("swapin/{address}/refund")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task SwapInRefund(string storeId, string address) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - return View((object) storeId); - } - - [HttpPost("swapin/{address}/refund")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task SwapInRefund(string storeId, string txid, uint vout, string refundAddress, uint? satPerByte = null) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - try - { - // Parse the txid:vout format from depositId if needed - var fee = new Fee.Rate((ulong)(satPerByte ?? 5m)); - var request = new RefundDepositRequest( - txid: txid, - vout: vout, - destinationAddress: refundAddress, - fee: fee - ); - - var resp = await client.Sdk.RefundDeposit(request); - TempData[WellKnownTempData.SuccessMessage] = $"Refund successful: {resp.txId}"; - } - catch (Exception e) - { - TempData[WellKnownTempData.ErrorMessage] = $"Couldnt refund: {e.Message}"; - } - - return RedirectToAction(nameof(SwapIn), new {storeId}); - } - - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - [HttpGet("configure")] - public async Task Configure(string storeId) - { - return View(await _breezService.Get(storeId)); - } - [HttpPost("configure")] - [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Configure(string storeId, string command, BreezSparkSettings settings) - { - var store = HttpContext.GetStoreData(); - if (store == null) - { - return NotFound(); - } - var pmi = new PaymentMethodId("BTC-LN"); - // In v2.2.1, payment methods are handled differently - // TODO: Implement proper v2.2.1 payment method handling - object? existing = null; - - if (command == "clear") - { - await _breezService.Set(storeId, null); - TempData[WellKnownTempData.SuccessMessage] = "Settings cleared successfully"; - var client = _breezService.GetClient(storeId); - // In v2.2.1, payment methods are handled differently - // TODO: Implement proper v2.2.1 payment method handling - return RedirectToAction(nameof(Configure), new {storeId}); - } - - if (command == "save") - { - try - { - if (string.IsNullOrEmpty(settings.Mnemonic)) - { - ModelState.AddModelError(nameof(settings.Mnemonic), "Mnemonic is required"); - return View(settings); - } - - try - { - new Mnemonic(settings.Mnemonic); - } - catch (Exception e) - { - ModelState.AddModelError(nameof(settings.Mnemonic), "Invalid mnemonic"); - return View(settings); - } - - await _breezService.Set(storeId, settings); - } - catch (Exception e) - { - TempData[WellKnownTempData.ErrorMessage] = $"Couldnt use provided settings: {e.Message}"; - return View(settings); - } - - // In v2.2.1, payment methods are handled differently - // TODO: Implement proper v2.2.1 payment method handling - // This will require a complete rewrite of the payment method system - - TempData[WellKnownTempData.SuccessMessage] = "Settings saved successfully"; - return RedirectToAction(nameof(Info), new {storeId}); - } - - return NotFound(); - } - - [Route("payments")] - [Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)] - public async Task Payments(string storeId, PaymentsViewModel viewModel) - { - var client = _breezService.GetClient(storeId); - if (client is null) - { - return RedirectToAction(nameof(Configure), new {storeId}); - } - - viewModel ??= new PaymentsViewModel(); - var req = new ListPaymentsRequest( - typeFilter: null, - statusFilter: null, - assetFilter: new AssetFilter.Bitcoin(), - fromTimestamp: null, - toTimestamp: null, - offset: viewModel.Skip != null ? (uint?)viewModel.Skip : null, - limit: viewModel.Count != null ? (uint?)viewModel.Count : null, - sortAscending: false - ); - var response = await client.Sdk.ListPayments(req); - viewModel.Payments = response.payments.Select(client.NormalizePayment).ToList(); - - return View(viewModel); - } -} - -public class PaymentsViewModel : BasePagingViewModel -{ - public List Payments { get; set; } = new(); - public override int CurrentPageCount => Payments.Count; -} - -// Helper class for swap information display in views -public class SwapInfo -{ - public string? bitcoinAddress { get; set; } - public ulong minAllowedDeposit { get; set; } - public ulong maxAllowedDeposit { get; set; } - public string? status { get; set; } -} - -// Helper class for swap limits display in views -public class SwapLimits -{ - public ulong min { get; set; } - public ulong max { get; set; } -} diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkLightningClient.cs b/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkLightningClient.cs deleted file mode 100644 index 446a28a..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkLightningClient.cs +++ /dev/null @@ -1,952 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using Breez.Sdk.Spark; -using BTCPayServer.Lightning; -using NBitcoin; -using Network = Breez.Sdk.Spark.Network; - -namespace BTCPayServer.Plugins.BreezSpark; - -public class EventLogEntry -{ - public DateTimeOffset timestamp { get; set; } - public string log { get; set; } = string.Empty; -} - -public class BreezSparkLightningClient : ILightningClient, IDisposable -{ - public override string ToString() - { - return $"type=breezspark;key={PaymentKey}"; - } - - private readonly NBitcoin.Network _network; - public readonly string PaymentKey; - - public ConcurrentQueue Events { get; set; } = new ConcurrentQueue(); - private readonly ConcurrentQueue _paymentNotifications = new(); - private readonly ConcurrentDictionary _seenCompletedPayments = new(); - private readonly ConcurrentDictionary _seenPaymentHashes = new(StringComparer.OrdinalIgnoreCase); - private readonly ConcurrentDictionary _invoicesByHash = new(StringComparer.OrdinalIgnoreCase); - private readonly ConcurrentDictionary _invoicesByBolt11 = new(StringComparer.OrdinalIgnoreCase); - - private void DebugLog(string message) - { - // Debug logging disabled for release build - } - - private void DebugLogObject(string label, object obj) - { - // Debug logging disabled for release build - } - - private BreezSdk _sdk; - - public static async Task Create(string apiKey, string workingDir, NBitcoin.Network network, - Mnemonic mnemonic, string paymentKey) - { - apiKey ??= "99010c6f84541bf582899db6728f6098ba98ca95ea569f4c63f2c2c9205ace57"; - - var config = BreezSdkSparkMethods.DefaultConfig( - network == NBitcoin.Network.Main ? Network.Mainnet : - network == NBitcoin.Network.RegTest ? Network.Regtest : Network.Mainnet - ) with - { - apiKey = apiKey - }; - - var seed = new Seed.Mnemonic(mnemonic: mnemonic.ToString(), passphrase: null); - var sdk = await BreezSdkSparkMethods.Connect(new ConnectRequest(config, seed, workingDir)); - - return new BreezSparkLightningClient(sdk, network, paymentKey); - } - - private BreezSparkLightningClient(BreezSdk sdk, NBitcoin.Network network, string paymentKey) - { - _sdk = sdk; - _network = network; - PaymentKey = paymentKey; - - // Start monitoring payment events - _ = Task.Run(MonitorPaymentEvents); - } - - public BreezSdk Sdk => _sdk; - - public async Task GetInvoice(string invoiceId, CancellationToken cancellation = default) - { - var invoice = await GetInvoiceInternal(invoiceId, cancellation); - if (invoice is not null) - { - return invoice; - } - - return new LightningInvoice() - { - Id = invoiceId, - PaymentHash = invoiceId, - Status = LightningInvoiceStatus.Unpaid - }; - } - - public async Task GetInvoice(uint256 paymentHash, CancellationToken cancellation = default) - { - return await GetInvoice(paymentHash.ToString(), cancellation); - } - - public async Task ListInvoices(CancellationToken cancellation = default) - { - return await ListInvoices((ListInvoicesParams?)null, cancellation); - } - - public async Task ListInvoices(ListInvoicesParams request, - CancellationToken cancellation = default) - { - var req = new ListPaymentsRequest( - typeFilter: new List { PaymentType.Receive }, - statusFilter: request?.PendingOnly == true ? new List { PaymentStatus.Pending } : null, - assetFilter: new AssetFilter.Bitcoin(), - fromTimestamp: null, - toTimestamp: null, - offset: request?.OffsetIndex != null ? (uint?)request.OffsetIndex : null, - limit: null, - sortAscending: false - ); - - var response = await _sdk.ListPayments(req); - return response.payments.Select(FromPayment).Where(p => p != null).ToArray(); - } - - public async Task GetPayment(string paymentHash, CancellationToken cancellation = default) - { - var payment = await FindPayment(paymentHash, cancellation); - return payment is not null ? ToLightningPayment(payment) : null; - } - - public async Task ListPayments(CancellationToken cancellation = default) - { - return await ListPayments((ListPaymentsParams?)null, cancellation); - } - - public async Task ListPayments(ListPaymentsParams request, - CancellationToken cancellation = default) - { - var req = new ListPaymentsRequest( - typeFilter: new List { PaymentType.Send }, - statusFilter: null, - assetFilter: new AssetFilter.Bitcoin(), - fromTimestamp: null, - toTimestamp: null, - offset: request?.OffsetIndex != null ? (uint?)request.OffsetIndex : null, - limit: null, - sortAscending: false - ); - - var response = await _sdk.ListPayments(req); - return response.payments.Select(ToLightningPayment).Where(p => p != null).ToArray(); - } - - public async Task CreateInvoice(LightMoney amount, string description, TimeSpan expiry, - CancellationToken cancellation = default) - { - var descriptionToUse = description ?? "Invoice"; - var amountSats = (ulong)amount.ToUnit(LightMoneyUnit.Satoshi); - var paymentMethod = new ReceivePaymentMethod.Bolt11Invoice(descriptionToUse, amountSats); - var response = await _sdk.ReceivePayment(new ReceivePaymentRequest(paymentMethod)); - DebugLogObject("ReceivePaymentResponse(CreateInvoice)", response); - return FromReceivePaymentResponse(response, amount); - } - - public async Task CreateInvoice(CreateInvoiceParams createInvoiceRequest, - CancellationToken cancellation = default) - { - var description = createInvoiceRequest.Description ?? createInvoiceRequest.DescriptionHash?.ToString() ?? "Invoice"; - var amountSats = (ulong)createInvoiceRequest.Amount.ToUnit(LightMoneyUnit.Satoshi); - var paymentMethod = new ReceivePaymentMethod.Bolt11Invoice(description, amountSats); - var response = await _sdk.ReceivePayment(new ReceivePaymentRequest(paymentMethod)); - DebugLogObject("ReceivePaymentResponse(CreateInvoiceParams)", response); - return FromReceivePaymentResponse(response, createInvoiceRequest.Amount); - } - - public async Task Listen(CancellationToken cancellation = default) - { - return new BreezSparkInvoiceListener(this, cancellation); - } - - public async Task GetInfo(CancellationToken cancellation = default) - { - try - { - var response = await _sdk.GetInfo(new GetInfoRequest(ensureSynced: false)); - - return new LightningNodeInformation() - { - Alias = "BreezSpark (nodeless)", - BlockHeight = 0, // Spark SDK doesn't expose block height - Version = "0.4.1" // SDK version hardcoded since property not found - }; - } - catch - { - return new LightningNodeInformation() - { - Alias = "BreezSpark (nodeless)", - BlockHeight = 0 - }; - } - } - - public async Task GetBalance(CancellationToken cancellation = default) - { - try - { - var response = await _sdk.GetInfo(new GetInfoRequest(ensureSynced: false)); - - return new LightningNodeBalance() - { - OnchainBalance = new OnchainBalance() - { - Confirmed = Money.Satoshis((long)response.balanceSats) - }, - OffchainBalance = new OffchainBalance() - { - Local = LightMoney.Satoshis((long)response.balanceSats), - Remote = LightMoney.Zero - } - }; - } - catch - { - return new LightningNodeBalance() - { - OnchainBalance = new OnchainBalance() - { - Confirmed = Money.Zero - }, - OffchainBalance = new OffchainBalance() - { - Local = LightMoney.Zero, - Remote = LightMoney.Zero - } - }; - } - } - - public async Task Pay(PayInvoiceParams payParams, CancellationToken cancellation = default) - { - return await Pay(null, payParams, cancellation); - } - - public async Task Pay(string bolt11, PayInvoiceParams payParams, - CancellationToken cancellation = default) - { - try - { - if (string.IsNullOrEmpty(bolt11)) - { - return new PayResponse(PayResult.Error, "BOLT11 invoice required"); - } - - BigInteger? amountSats = null; - if (payParams.Amount > 0) - { - amountSats = new BigInteger(payParams.Amount); - } - - var prepareRequest = new PrepareSendPaymentRequest( - paymentRequest: bolt11, - amount: amountSats - ); - var prepareResponse = await _sdk.PrepareSendPayment(prepareRequest); - - if (prepareResponse.paymentMethod is SendPaymentMethod.Bolt11Invoice bolt11Method) - { - var options = new SendPaymentOptions.Bolt11Invoice( - preferSpark: false, - completionTimeoutSecs: 60 - ); - - var sendRequest = new SendPaymentRequest( - prepareResponse: prepareResponse, - options: options - ); - var sendResponse = await _sdk.SendPayment(sendRequest); - - return new PayResponse() - { - Result = sendResponse.payment.status switch - { - PaymentStatus.Failed => PayResult.Error, - PaymentStatus.Completed => PayResult.Ok, - PaymentStatus.Pending => PayResult.Unknown, - _ => PayResult.Error - }, - Details = new PayDetails() - { - Status = sendResponse.payment.status switch - { - PaymentStatus.Failed => LightningPaymentStatus.Failed, - PaymentStatus.Completed => LightningPaymentStatus.Complete, - PaymentStatus.Pending => LightningPaymentStatus.Pending, - _ => LightningPaymentStatus.Unknown - }, - TotalAmount = LightMoney.Satoshis((long)(sendResponse.payment.amount / 1000)), - FeeAmount = (long)(bolt11Method.lightningFeeSats + (bolt11Method.sparkTransferFeeSats ?? 0)) - } - }; - } - else - { - return new PayResponse(PayResult.Error, "Invalid payment method"); - } - } - catch (Exception e) - { - return new PayResponse(PayResult.Error, e.Message); - } - } - - public async Task Pay(string bolt11, CancellationToken cancellation = default) - { - return await Pay(bolt11, null, cancellation); - } - - public async Task OpenChannel(OpenChannelRequest openChannelRequest, - CancellationToken cancellation = default) - { - throw new NotImplementedException(); - } - - public async Task GetDepositAddress(CancellationToken cancellation = default) - { - throw new NotImplementedException(); - } - - public async Task ConnectTo(NodeInfo nodeInfo, CancellationToken cancellation = default) - { - throw new NotImplementedException(); - } - - public async Task CancelInvoice(string invoiceId, CancellationToken cancellation = default) - { - throw new NotImplementedException(); - } - - public async Task ListChannels(CancellationToken cancellation = default) - { - throw new NotImplementedException(); - } - - private LightningInvoice FromReceivePaymentResponse(ReceivePaymentResponse response, LightMoney requestedAmount) - { - string? paymentHash = null; - try - { - if (BOLT11PaymentRequest.TryParse(response.paymentRequest, out var pr, _network)) - { - paymentHash = pr.PaymentHash?.ToString(); - } - } - catch - { - // Ignore parse errors and fall back to raw request - } - - DebugLogObject("FromReceivePaymentResponse", response); - RecordInvoiceAmount(response.paymentRequest, paymentHash, requestedAmount); - - return new LightningInvoice() - { - Id = paymentHash ?? response.paymentRequest, - PaymentHash = paymentHash, - BOLT11 = response.paymentRequest, - Status = LightningInvoiceStatus.Unpaid, - Amount = requestedAmount - }; - } - - private LightningInvoice FromPayment(Payment payment) - { - if (payment == null) return null; - - string paymentHash = ExtractPaymentHash(payment); - string bolt11 = null; - LightMoney? boltAmount = null; - LightMoney? recordedAmount = null; - - if (payment.details is PaymentDetails.Lightning lightningDetails) - { - bolt11 = lightningDetails.invoice; - if (!string.IsNullOrEmpty(lightningDetails.invoice) && - BOLT11PaymentRequest.TryParse(lightningDetails.invoice, out var pr, _network)) - { - boltAmount = pr.MinimumAmount; - } - - var rec = LookupInvoice(lightningDetails.invoice, paymentHash); - recordedAmount = rec?.Amount; - } - - // Reject if hash is missing or not one we issued - if (string.IsNullOrEmpty(paymentHash)) - { - DebugLog($"FromPayment: missing payment hash for payment.id={payment.id}"); - return null; - } - - var record = LookupInvoice(null, paymentHash); - if (record is null || record.PaymentHash != paymentHash) - { - DebugLog($"FromPayment: unknown payment hash={paymentHash} payment.id={payment.id}"); - return null; - } - - recordedAmount ??= record.Amount; - - // Always use the invoice amount (BOLT11 truth). Never fall back to what Breez reports. - var resolvedAmount = recordedAmount ?? boltAmount; - if (boltAmount is not null && recordedAmount is not null && boltAmount != recordedAmount) - { - DebugLog($"FromPayment: bolt amount {boltAmount.ToUnit(LightMoneyUnit.Satoshi)} != recorded {recordedAmount.ToUnit(LightMoneyUnit.Satoshi)} for hash={paymentHash}"); - } - - var invoiceId = paymentHash; - if (resolvedAmount is null) - { - DebugLog($"FromPayment: missing amount for hash={paymentHash} bolt11={Shorten(bolt11)}"); - return null; - } - - DebugLog($"FromPayment: returning invoice id={invoiceId} hash={paymentHash} bolt11={Shorten(bolt11)} boltSat={boltAmount?.ToUnit(LightMoneyUnit.Satoshi)} recSat={recordedAmount?.ToUnit(LightMoneyUnit.Satoshi)} raw_msat={payment.amount} fee_msat={payment.fees} chosenSat={resolvedAmount.ToUnit(LightMoneyUnit.Satoshi)}"); - - return new LightningInvoice() - { - Id = invoiceId, - PaymentHash = paymentHash ?? invoiceId, - BOLT11 = bolt11 ?? payment.id, - Amount = resolvedAmount, - AmountReceived = resolvedAmount, - Status = payment.status switch - { - PaymentStatus.Pending => LightningInvoiceStatus.Unpaid, - PaymentStatus.Failed => LightningInvoiceStatus.Expired, - PaymentStatus.Completed => LightningInvoiceStatus.Paid, - _ => LightningInvoiceStatus.Unpaid - }, - PaidAt = DateTimeOffset.FromUnixTimeSeconds((long)payment.timestamp) - }; - } - - private LightningPayment ToLightningPayment(Payment payment) - { - if (payment == null) return null; - - string paymentHash = ExtractPaymentHash(payment); - string preimage = null; - string bolt11 = null; - LightMoney? boltAmount = null; - LightMoney? recordedAmount = null; - var feeAmount = GetFeeFromPayment(payment); - - if (payment.details is PaymentDetails.Lightning lightningDetails) - { - preimage = lightningDetails.preimage; - bolt11 = lightningDetails.invoice; - if (!string.IsNullOrEmpty(lightningDetails.invoice) && - BOLT11PaymentRequest.TryParse(lightningDetails.invoice, out var pr, _network)) - { - boltAmount = pr.MinimumAmount; - } - - var rec = LookupInvoice(lightningDetails.invoice, paymentHash); - recordedAmount = rec?.Amount; - } - - if (string.IsNullOrEmpty(paymentHash)) - { - DebugLog($"ToLightningPayment: missing payment hash for payment.id={payment.id}"); - return null; - } - - var record = LookupInvoice(null, paymentHash); - if (record is null || record.PaymentHash != paymentHash) - { - DebugLog($"ToLightningPayment: unknown payment hash={paymentHash} payment.id={payment.id}"); - return null; - } - - recordedAmount ??= record.Amount; - - var resolvedAmount = recordedAmount ?? boltAmount; - if (boltAmount is not null && recordedAmount is not null && boltAmount != recordedAmount) - { - DebugLog($"ToLightningPayment: bolt amount {boltAmount.ToUnit(LightMoneyUnit.Satoshi)} != recorded {recordedAmount.ToUnit(LightMoneyUnit.Satoshi)} for hash={paymentHash}"); - } - - var paymentId = paymentHash; - if (resolvedAmount is null) - { - DebugLog($"ToLightningPayment: missing amount for hash={paymentHash} bolt11={Shorten(bolt11)}"); - return null; - } - - DebugLog($"ToLightningPayment: returning payment id={paymentId} hash={paymentHash} bolt11={Shorten(bolt11)} boltSat={boltAmount?.ToUnit(LightMoneyUnit.Satoshi)} recSat={recordedAmount?.ToUnit(LightMoneyUnit.Satoshi)} raw_msat={payment.amount} fee_msat={payment.fees} chosenSat={resolvedAmount.ToUnit(LightMoneyUnit.Satoshi)}"); - - return new LightningPayment() - { - Id = paymentId, - PaymentHash = paymentHash ?? paymentId, - Preimage = preimage, - BOLT11 = bolt11, - Amount = resolvedAmount, - Status = payment.status switch - { - PaymentStatus.Failed => LightningPaymentStatus.Failed, - PaymentStatus.Completed => LightningPaymentStatus.Complete, - PaymentStatus.Pending => LightningPaymentStatus.Pending, - _ => LightningPaymentStatus.Unknown - }, - CreatedAt = DateTimeOffset.FromUnixTimeSeconds((long)payment.timestamp), - Fee = feeAmount, - AmountSent = resolvedAmount - }; - } - - private void RecordInvoiceAmount(string bolt11, string? paymentHash, LightMoney requestedAmount) - { - // Prefer the amount encoded in the BOLT11 (ground truth), fall back to the requested amount. - LightMoney amount = requestedAmount; - try - { - if (BOLT11PaymentRequest.TryParse(bolt11, out var pr, _network)) - { - if (pr.MinimumAmount is not null) - amount = pr.MinimumAmount; - if (string.IsNullOrEmpty(paymentHash) && pr.PaymentHash is not null) - paymentHash = pr.PaymentHash.ToString(); - } - } - catch { } - - if (string.IsNullOrEmpty(paymentHash)) - return; - - var record = new InvoiceRecord - { - PaymentHash = paymentHash, - Bolt11 = bolt11, - Amount = amount - }; - - _invoicesByHash[paymentHash] = record; - _invoicesByBolt11[bolt11] = record; - } - - private InvoiceRecord? LookupInvoice(string? bolt11, string? paymentHash) - { - if (!string.IsNullOrEmpty(paymentHash) && _invoicesByHash.TryGetValue(paymentHash, out var recByHash)) - { - DebugLog($"LookupInvoice: hit by hash={paymentHash} amount_sat={recByHash.Amount.ToUnit(LightMoneyUnit.Satoshi)} bolt11={Shorten(recByHash.Bolt11)}"); - return recByHash; - } - - if (!string.IsNullOrEmpty(bolt11) && _invoicesByBolt11.TryGetValue(bolt11, out var recByBolt)) - { - DebugLog($"LookupInvoice: hit by bolt11={Shorten(bolt11)} amount_sat={recByBolt.Amount.ToUnit(LightMoneyUnit.Satoshi)}"); - return recByBolt; - } - - DebugLog($"LookupInvoice: miss for hash={paymentHash} bolt11={Shorten(bolt11)}"); - return null; - } - - private bool IsKnownPayment(Payment payment) - { - var paymentHash = ExtractPaymentHash(payment); - if (string.IsNullOrEmpty(paymentHash)) - return false; - - return LookupInvoice(null, paymentHash) is not null; - } - - private LightMoney InferAmountFromPayment(Payment payment) - { - var rawAmount = payment.amount; - - if (rawAmount == 0) - { - return LightMoney.Zero; - } - - // Breez SDK surfaces amounts in millisats for lightning payments; fall back to sats otherwise. - if (rawAmount % 1000 == 0) - { - return LightMoney.Satoshis((long)(rawAmount / 1000)); - } - - return LightMoney.Satoshis((long)rawAmount); - } - - private string? ExtractPaymentHash(Payment payment) - { - if (payment?.details is not PaymentDetails.Lightning ln) - return null; - - if (!string.IsNullOrEmpty(ln.paymentHash)) - return ln.paymentHash; - - if (!string.IsNullOrEmpty(ln.invoice) && - BOLT11PaymentRequest.TryParse(ln.invoice, out var pr, _network) && - pr.PaymentHash is not null) - { - return pr.PaymentHash.ToString(); - } - - return null; - } - - private LightMoney GetFeeFromPayment(Payment payment) - { - return payment.fees % 1000 == 0 - ? LightMoney.Satoshis((long)(payment.fees / 1000)) - : LightMoney.Satoshis((long)payment.fees); - } - - private bool TryMarkPaymentSeen(Payment payment) - { - var paymentHash = ExtractPaymentHash(payment); - var seenByHash = !string.IsNullOrEmpty(paymentHash) && _seenPaymentHashes.ContainsKey(paymentHash); - var seenById = _seenCompletedPayments.ContainsKey(payment.id); - if (seenByHash || seenById) - { - DebugLog($"TryMarkPaymentSeen: already seen payment.id={payment.id} hash={paymentHash}"); - return false; - } - - _seenCompletedPayments.TryAdd(payment.id, true); - if (!string.IsNullOrEmpty(paymentHash)) - { - _seenPaymentHashes.TryAdd(paymentHash, true); - } - - return true; - } - - public NormalizedPayment NormalizePayment(Payment payment) - { - if (payment == null) throw new ArgumentNullException(nameof(payment)); - - string paymentHash = null; - string bolt11 = null; - string description = null; - LightMoney? boltAmount = null; - LightMoney? recordedAmount = null; - var feeAmount = GetFeeFromPayment(payment); - - if (payment.details is PaymentDetails.Lightning lightningDetails) - { - paymentHash = ExtractPaymentHash(payment); - bolt11 = lightningDetails.invoice; - description = lightningDetails.description; - if (!string.IsNullOrEmpty(lightningDetails.invoice) && - BOLT11PaymentRequest.TryParse(lightningDetails.invoice, out var pr, _network)) - { - boltAmount = pr.MinimumAmount; - } - - var rec = LookupInvoice(lightningDetails.invoice, lightningDetails.paymentHash); - recordedAmount = rec?.Amount; - } - - if (string.IsNullOrEmpty(paymentHash)) - { - DebugLog($"NormalizePayment: missing payment hash for payment.id={payment.id}"); - return null; - } - - var record = LookupInvoice(null, paymentHash); - if (record is null || record.PaymentHash != paymentHash) - { - DebugLog($"NormalizePayment: unknown payment hash={paymentHash} payment.id={payment.id}"); - return null; - } - - recordedAmount ??= record.Amount; - var amount = recordedAmount ?? boltAmount; - if (boltAmount is not null && recordedAmount is not null && boltAmount != recordedAmount) - { - DebugLog($"NormalizePayment: bolt amount {boltAmount.ToUnit(LightMoneyUnit.Satoshi)} != recorded {recordedAmount.ToUnit(LightMoneyUnit.Satoshi)} for hash={paymentHash}"); - } - - if (amount is null) - { - // If we can't prove the amount from the BOLT11 or stored record, reject the payment. - DebugLog($"NormalizePayment: missing amount for hash={paymentHash} bolt11={Shorten(bolt11)}"); - return null; - } - var fee = feeAmount; - - return new NormalizedPayment - { - Id = paymentHash ?? bolt11 ?? payment.id, - PaymentType = payment.paymentType, - Status = payment.status, - Timestamp = payment.timestamp, - Amount = amount, - Fee = fee, - Description = description ?? bolt11 - }; - } - - public void Dispose() - { - _sdk?.Dispose(); - } - - public class BreezSparkInvoiceListener : ILightningInvoiceListener - { - private readonly BreezSparkLightningClient _breezLightningClient; - private readonly CancellationToken _cancellationToken; - private readonly ConcurrentQueue _invoices = new(); - - public BreezSparkInvoiceListener(BreezSparkLightningClient breezLightningClient, CancellationToken cancellationToken) - { - _breezLightningClient = breezLightningClient; - _cancellationToken = cancellationToken; - } - - public void Dispose() - { - } - - public async Task WaitInvoice(CancellationToken cancellation) - { - using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_cancellationToken, cancellation); - - while (!linkedCts.Token.IsCancellationRequested) - { - // Check the client's payment notification queue - if (_breezLightningClient._paymentNotifications.TryDequeue(out var payment)) - { - var invoice = _breezLightningClient.FromPayment(payment); - if (invoice is not null) - { - _breezLightningClient.DebugLog($"WaitInvoice: dequeued payment.id={payment.id} hash={invoice.PaymentHash} bolt11={_breezLightningClient.Shorten(invoice.BOLT11)} status={payment.status} raw_msat={payment.amount} fee_msat={payment.fees}"); - // Force amount to the recorded invoice amount (BOLT11 truth) before handing to BTCPay - var rec = _breezLightningClient.LookupInvoice(invoice.BOLT11, invoice.PaymentHash); - if (rec is not null) - { - invoice.Amount = rec.Amount; - invoice.AmountReceived = rec.Amount; - _breezLightningClient.DebugLog($"WaitInvoice: normalized invoice amount to recorded {rec.Amount.ToUnit(LightMoneyUnit.Satoshi)} sats for hash={invoice.PaymentHash}"); - } - return invoice; - } - } - - // Also check the local queue for backwards compatibility - if (_invoices.TryDequeue(out var payment2)) - { - var invoice = _breezLightningClient.FromPayment(payment2); - if (invoice is not null) - { - _breezLightningClient.DebugLog($"WaitInvoice(local): dequeued payment.id={payment2.id} hash={invoice.PaymentHash} bolt11={_breezLightningClient.Shorten(invoice.BOLT11)} status={payment2.status} raw_msat={payment2.amount} fee_msat={payment2.fees}"); - var rec = _breezLightningClient.LookupInvoice(invoice.BOLT11, invoice.PaymentHash); - if (rec is not null) - { - invoice.Amount = rec.Amount; - invoice.AmountReceived = rec.Amount; - _breezLightningClient.DebugLog($"WaitInvoice: normalized (local queue) invoice amount to recorded {rec.Amount.ToUnit(LightMoneyUnit.Satoshi)} sats for hash={invoice.PaymentHash}"); - } - return invoice; - } - } - - await Task.Delay(1000, linkedCts.Token); // Check every second - } - - linkedCts.Token.ThrowIfCancellationRequested(); - return null; - } - } - - private async Task MonitorPaymentEvents() - { - try - { - while (true) - { - try - { - // Get all payments and check for new paid ones - var payments = await _sdk.ListPayments(new ListPaymentsRequest( - typeFilter: new List { PaymentType.Receive } - )); - - foreach (var payment in payments.payments) - { - // If payment is complete, add it to the notification queue - if (payment.status == PaymentStatus.Completed && - TryMarkPaymentSeen(payment) && - IsKnownPayment(payment)) - { - DebugLogObject("MonitorPaymentEvents:payment", payment); - LogCompletedPayment(payment); - _paymentNotifications.Enqueue(payment); - } - } - - await Task.Delay(5000); // Poll every 5 seconds - } - catch (Exception ex) - { - // Log error but continue monitoring - Console.WriteLine($"Error monitoring BreezSpark payments: {ex.Message}"); - await Task.Delay(10000); // Wait longer on error - } - } - } - catch (Exception ex) - { - Console.WriteLine($"BreezSpark payment monitoring stopped: {ex.Message}"); - } - } - - public void AddPaymentNotification(Payment payment) - { - if (TryMarkPaymentSeen(payment) && - IsKnownPayment(payment)) - { - DebugLogObject("AddPaymentNotification:payment", payment); - LogCompletedPayment(payment); - _paymentNotifications.Enqueue(payment); - } - } - - public async Task<(LightningInvoice Invoice, long FeeSats)> CreateInvoiceWithFee(CreateInvoiceParams createInvoiceRequest, CancellationToken cancellation = default) - { - var description = createInvoiceRequest.Description ?? createInvoiceRequest.DescriptionHash?.ToString() ?? "Invoice"; - var amountSats = (ulong)createInvoiceRequest.Amount.ToUnit(LightMoneyUnit.Satoshi); - var paymentMethod = new ReceivePaymentMethod.Bolt11Invoice(description, amountSats); - var response = await _sdk.ReceivePayment(new ReceivePaymentRequest(paymentMethod)); - var feeSats = (long)response.fee; - var invoice = FromReceivePaymentResponse(response, createInvoiceRequest.Amount); - return (invoice, feeSats); - } - - private async Task GetInvoiceInternal(string identifier, CancellationToken cancellation) - { - var payment = await FindPayment(identifier, cancellation); - if (payment is null) - return null; - - // Deduplicate completed payments so LightningListener doesn't try to add the same payment twice. - if (payment.status == PaymentStatus.Completed && !TryMarkPaymentSeen(payment)) - { - return null; - } - - return FromPayment(payment); - } - - private async Task FindPayment(string identifier, CancellationToken cancellation) - { - try - { - var byId = await _sdk.GetPayment(new GetPaymentRequest(identifier)); - DebugLogObject("FindPayment:GetPayment", byId); - if (byId?.payment != null && IsKnownPayment(byId.payment)) - { - return byId.payment; - } - } - catch - { - // Ignore and fallback to listing payments - } - - try - { - var list = await _sdk.ListPayments(new ListPaymentsRequest( - typeFilter: new List { PaymentType.Receive }, - assetFilter: new AssetFilter.Bitcoin() - )); - DebugLogObject("FindPayment:ListPayments", list); - - return list.payments.FirstOrDefault(p => - { - if (p.details is PaymentDetails.Lightning lightning) - { - if (!IsKnownPayment(p)) - return false; - - return lightning.paymentHash == identifier || - lightning.invoice == identifier; - } - - return p.id == identifier; - }); - } - catch - { - return null; - } - } - - private void LogCompletedPayment(Payment payment) - { - try - { - string paymentHash = ExtractPaymentHash(payment); - string bolt11 = null; - LightMoney? boltAmount = null; - if (payment.details is PaymentDetails.Lightning ln) - { - bolt11 = ln.invoice; - if (!string.IsNullOrEmpty(bolt11) && - BOLT11PaymentRequest.TryParse(bolt11, out var pr, _network)) - { - boltAmount = pr.MinimumAmount; - } - } - - var record = LookupInvoice(bolt11, paymentHash); - var recAmount = record?.Amount.ToUnit(LightMoneyUnit.Satoshi); - var rawAmount = payment.amount; - var fee = payment.fees; - var grossSat = InferAmountFromPayment(payment).ToUnit(LightMoneyUnit.Satoshi) + - GetFeeFromPayment(payment).ToUnit(LightMoneyUnit.Satoshi); - var boltSat = boltAmount?.ToUnit(LightMoneyUnit.Satoshi); - } - catch - { - // best-effort logging - } - } - - private string Shorten(string? s, int head = 6, int tail = 6) - { - if (string.IsNullOrEmpty(s)) - return string.Empty; - if (s.Length <= head + tail + 3) - return s; - return $"{s.Substring(0, head)}...{s.Substring(s.Length - tail)}"; - } -} - -public class NormalizedPayment -{ - public string Id { get; set; } = string.Empty; - public PaymentType PaymentType { get; set; } - public PaymentStatus Status { get; set; } - public ulong Timestamp { get; set; } - public LightMoney Amount { get; set; } = LightMoney.Zero; - public LightMoney Fee { get; set; } = LightMoney.Zero; - public string? Description { get; set; } -} diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkLightningConnectionStringHandler.cs b/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkLightningConnectionStringHandler.cs deleted file mode 100644 index ab17607..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkLightningConnectionStringHandler.cs +++ /dev/null @@ -1,33 +0,0 @@ -using BTCPayServer.Lightning; -using NBitcoin; - -namespace BTCPayServer.Plugins.BreezSpark; - -public class BreezSparkLightningConnectionStringHandler : ILightningConnectionStringHandler -{ - private readonly BreezSparkService _breezService; - - public BreezSparkLightningConnectionStringHandler(BreezSparkService breezService) - { - _breezService = breezService; - } - public ILightningClient? Create(string connectionString, Network network, out string? error) - { - var kv = LightningConnectionStringHelper.ExtractValues(connectionString, out var type); - if (type != "breezspark") - { - error = null; - return null; - } - - - if (!kv.TryGetValue("key", out var key)) - { - error = $"The key 'key' is mandatory for breezspark connection strings"; - return null; - } - - error = null; - return _breezService.GetClientByPaymentKey(key); - } -} diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkPaymentMethodHandler.cs b/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkPaymentMethodHandler.cs deleted file mode 100644 index 35ecd32..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkPaymentMethodHandler.cs +++ /dev/null @@ -1,162 +0,0 @@ -#nullable enable -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using BTCPayServer.Client; -using BTCPayServer.Client.Models; -using BTCPayServer.Configuration; -using BTCPayServer.Data; -using BTCPayServer.Lightning; -using BTCPayServer.Payments; -using BTCPayServer.Payments.Lightning; -using BTCPayServer.Services; -using BTCPayServer.Services.Invoices; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; -using NBitcoin; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace BTCPayServer.Plugins.BreezSpark -{ - public class BreezSparkPaymentMethodConfig : LightningPaymentMethodConfig - { - public string PaymentKey { get; set; } = string.Empty; - public string StoreId { get; set; } = string.Empty; - } - - public class BreezSparkPaymentMethodHandler : IPaymentMethodHandler, ILightningPaymentHandler - { - private readonly BreezSparkService _breezService; - private readonly PaymentMethodId _paymentMethodId; - private readonly BTCPayNetwork _network; - private readonly LightningClientFactoryService _lightningClientFactory; - private readonly IOptions _lightningNetworkOptions; - public JsonSerializer Serializer { get; } - - public BreezSparkPaymentMethodHandler( - BreezSparkService breezService, - BTCPayNetwork network, - LightningClientFactoryService lightningClientFactory, - IOptions lightningNetworkOptions) - { - _breezService = breezService; - _network = network; - _lightningClientFactory = lightningClientFactory; - _lightningNetworkOptions = lightningNetworkOptions; - _paymentMethodId = PaymentMethodId.Parse("BTC-BreezSpark"); - Serializer = BlobSerializer.CreateSerializer(network.NBitcoinNetwork).Serializer; - } - - public PaymentMethodId PaymentMethodId => _paymentMethodId; - - public BTCPayNetwork Network => _network; - - public Task BeforeFetchingRates(PaymentMethodContext context) - { - context.Prompt.Currency = _network.CryptoCode; - context.Prompt.PaymentMethodFee = 0m; - context.Prompt.Divisibility = 11; - context.Prompt.RateDivisibility = 8; - return Task.CompletedTask; - } - - public async Task ConfigurePrompt(PaymentMethodContext context) - { - if (context.InvoiceEntity.Type == InvoiceType.TopUp) - { - throw new PaymentMethodUnavailableException("BreezSpark Lightning Network payment method is not available for top-up invoices"); - } - - var paymentPrompt = context.Prompt; - var storeBlob = context.StoreBlob; - var store = context.Store; - - // Parse BreezSpark-specific config - var breezConfig = ParsePaymentMethodConfig(context.PaymentMethodConfig); - if (breezConfig == null || string.IsNullOrEmpty(breezConfig.PaymentKey)) - { - throw new PaymentMethodUnavailableException("BreezSpark payment key is not configured"); - } - - // Get BreezSpark client - var breezClient = _breezService.GetClient(breezConfig.StoreId); - if (breezClient == null) - { - throw new PaymentMethodUnavailableException("BreezSpark client is not available for this store"); - } - - var invoice = context.InvoiceEntity; - decimal due = paymentPrompt.Calculate().Due; - var expiry = invoice.ExpirationTime - DateTimeOffset.UtcNow; - if (expiry < TimeSpan.Zero) - expiry = TimeSpan.FromSeconds(1); - - LightningInvoice lightningInvoice; - string description = storeBlob.LightningDescriptionTemplate; - description = description.Replace("{StoreName}", store.StoreName ?? "", StringComparison.OrdinalIgnoreCase) - .Replace("{ItemDescription}", invoice.Metadata.ItemDesc ?? "", StringComparison.OrdinalIgnoreCase) - .Replace("{OrderId}", invoice.Metadata.OrderId ?? "", StringComparison.OrdinalIgnoreCase); - - try - { - var request = new CreateInvoiceParams( - new LightMoney(due, LightMoneyUnit.BTC), - description, - expiry); - request.PrivateRouteHints = storeBlob.LightningPrivateRouteHints; - - lightningInvoice = await breezClient.CreateInvoice(request, CancellationToken.None); - } - catch (Exception ex) - { - throw new PaymentMethodUnavailableException($"Impossible to create BreezSpark lightning invoice ({ex.Message})", ex); - } - - paymentPrompt.Destination = lightningInvoice.BOLT11; - var details = new LigthningPaymentPromptDetails - { - PaymentHash = lightningInvoice.GetPaymentHash(_network.NBitcoinNetwork), - Preimage = string.IsNullOrEmpty(lightningInvoice.Preimage) ? null : uint256.Parse(lightningInvoice.Preimage), - InvoiceId = lightningInvoice.Id, - NodeInfo = "BreezSpark Lightning Wallet" - }; - paymentPrompt.Details = JObject.FromObject(details, Serializer); - } - - public BreezSparkPaymentMethodConfig ParsePaymentMethodConfig(JToken config) - { - return config.ToObject(Serializer) ?? new BreezSparkPaymentMethodConfig(); - } - - object IPaymentMethodHandler.ParsePaymentMethodConfig(JToken config) - { - return ParsePaymentMethodConfig(config); - } - - public Task CreateLightningClient(LightningPaymentMethodConfig config) - { - var breezConfig = config as BreezSparkPaymentMethodConfig; - if (breezConfig == null || string.IsNullOrEmpty(breezConfig.StoreId)) - return Task.FromResult(null); - - return Task.FromResult(_breezService.GetClient(breezConfig.StoreId)); - } - - public object ParsePaymentPromptDetails(JToken details) - { - return details.ToObject(Serializer); - } - - public LightningPaymentData ParsePaymentDetails(JToken details) - { - return details.ToObject(Serializer); - } - - object IPaymentMethodHandler.ParsePaymentDetails(JToken details) - { - return ParsePaymentDetails(details); - } - } -} diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkPlugin.cs b/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkPlugin.cs deleted file mode 100644 index 6a7129e..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkPlugin.cs +++ /dev/null @@ -1,58 +0,0 @@ -#nullable enable -using BTCPayServer.Abstractions.Contracts; -using BTCPayServer.Abstractions.Models; -using BTCPayServer.Abstractions.Services; -using BTCPayServer.Configuration; -using BTCPayServer.Lightning; -using BTCPayServer.Payments; -using BTCPayServer.Services; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using NBitcoin; -using System; - -namespace BTCPayServer.Plugins.BreezSpark -{ - public class BreezSparkPlugin : BaseBTCPayServerPlugin - { - public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } = - { - new() { Identifier = nameof(BTCPayServer), Condition = ">=2.2.0" } - }; - - public override void Execute(IServiceCollection applicationBuilder) - { - applicationBuilder.AddSingleton(); - applicationBuilder.AddSingleton(provider => provider.GetRequiredService()); - applicationBuilder.AddSingleton(); - applicationBuilder.AddSingleton(provider => provider.GetRequiredService()); - - // Register the BreezSpark payment method handler - applicationBuilder.AddSingleton(provider => - { - var breezService = provider.GetRequiredService(); - var networkProvider = provider.GetRequiredService(); - var lightningClientFactory = provider.GetRequiredService(); - var lightningNetworkOptions = provider.GetRequiredService>(); - - return new BreezSparkPaymentMethodHandler( - breezService, - networkProvider.GetNetwork("BTC"), - lightningClientFactory, - lightningNetworkOptions); - }); - - // Add UI extensions for lightning setup tab (like Boltz does) - applicationBuilder.AddSingleton(new UIExtension("BreezSpark/LNPaymentMethodSetupTab", - "ln-payment-method-setup-tab")); - applicationBuilder.AddSingleton(new UIExtension("BreezSpark/LNPaymentMethodSetupTabhead", - "ln-payment-method-setup-tabhead")); - - // Surface BreezSpark navigation inside the store integrations nav, matching the plugin template pattern. - applicationBuilder.AddUIExtension("store-integrations-nav", "BreezSpark/BreezSparkNav"); - - base.Execute(applicationBuilder); - } - } -} diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkService.cs b/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkService.cs deleted file mode 100644 index 541f1be..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkService.cs +++ /dev/null @@ -1,181 +0,0 @@ -#nullable enable -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using BTCPayServer.Configuration; -using BTCPayServer.Data; -using BTCPayServer.HostedServices; -using BTCPayServer.Payments; -using BTCPayServer.Payments.Lightning; -using BTCPayServer.Services.Invoices; -using BTCPayServer.Services.Stores; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using NBitcoin; - -namespace BTCPayServer.Plugins.BreezSpark; - -public class BreezSparkService:EventHostedServiceBase -{ - private readonly StoreRepository _storeRepository; - private readonly IOptions _dataDirectories; - private readonly IServiceProvider _serviceProvider; - private PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary => _serviceProvider.GetRequiredService(); - private readonly ILogger _logger; - private Dictionary _settings = new(); - private Dictionary _clients = new(); - - public BreezSparkService( - EventAggregator eventAggregator, - StoreRepository storeRepository, - IOptions dataDirectories, - IServiceProvider serviceProvider, - ILogger logger) : base(eventAggregator, logger) - { - _storeRepository = storeRepository; - _dataDirectories = dataDirectories; - _serviceProvider = serviceProvider; - _logger = logger; - } - - protected override void SubscribeToEvents() - { - base.SubscribeToEvents(); - } - - protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken) - { - await base.ProcessEvent(evt, cancellationToken); - } - - public string GetWorkDir(string storeId) - { - var dir = _dataDirectories.Value.DataDir; - return Path.Combine(dir, "Plugins", "BreezSpark",storeId); - } - - TaskCompletionSource tcs = new(); - public override async Task StartAsync(CancellationToken cancellationToken) - { - _settings = (await _storeRepository.GetSettingsAsync("BreezSpark")).Where(pair => pair.Value is not null).ToDictionary(pair => pair.Key, pair => pair.Value!); - foreach (var keyValuePair in _settings) - { - try - { - - await Handle(keyValuePair.Key, keyValuePair.Value); - } - catch - { - } - } - tcs.TrySetResult(); - await base.StartAsync(cancellationToken); - } - - public async Task Get(string storeId) - { - await tcs.Task; - _settings.TryGetValue(storeId, out var settings); - - return settings; - } - - public async Task Handle(string? storeId, BreezSparkSettings? settings) - { - if (settings is null) - { - if (storeId is not null && _clients.Remove(storeId, out var client)) - { - client.Dispose(); - } - } - else - { - try - { - var network = Network.Main; - var dir = GetWorkDir(storeId); - Directory.CreateDirectory(dir); - settings.PaymentKey ??= Guid.NewGuid().ToString(); - - var client = await BreezSparkLightningClient.Create( - settings.ApiKey, - dir, - network, - new Mnemonic(settings.Mnemonic), - settings.PaymentKey - ); - - if (storeId is not null) - { - _clients.AddOrReplace(storeId, client); - } - - return client; - } - catch (Exception e) - { - _logger.LogError(e, "Could not create BreezSpark client"); - throw; - } - } - - return null; - } - - public async Task Set(string storeId, BreezSparkSettings? settings) - { - - var result = await Handle(storeId, settings); - await _storeRepository.UpdateSetting(storeId, "BreezSpark", settings!); - if (settings is null) - { - _settings.Remove(storeId, out var oldSettings ); - var data = await _storeRepository.FindStore(storeId); - if (data != null) - { - var pmi = new PaymentMethodId("BTC-LN"); - // In v2.2.1, the payment methods are handled differently - // We'll skip this for now as it needs to be refactored completely - // TODO: Implement proper v2.2.1 payment method handling - } - Directory.Delete(GetWorkDir(storeId), true); - - } - else if(result is not null ) - { - _settings.AddOrReplace(storeId, settings); - } - - - } - - public new async Task StopAsync(CancellationToken cancellationToken) - { - _clients.Values.ToList().ForEach(c => c.Dispose()); - await base.StopAsync(cancellationToken); - } - - public BreezSparkLightningClient? GetClient(string? storeId) - { - - tcs.Task.GetAwaiter().GetResult(); - if(storeId is null) - return null; - _clients.TryGetValue(storeId, out var client); - return client; - } - public BreezSparkLightningClient? GetClientByPaymentKey(string? paymentKey) - { - tcs.Task.GetAwaiter().GetResult(); - if(paymentKey is null) - return null; - var match = _settings.FirstOrDefault(pair => pair.Value.PaymentKey == paymentKey).Key; - return GetClient(match); - } -} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkSettings.cs b/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkSettings.cs deleted file mode 100644 index b5ce980..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/BreezSparkSettings.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable enable -using System; -using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; - -namespace BTCPayServer.Plugins.BreezSpark; - -public class BreezSparkSettings -{ - public string? Mnemonic { get; set; } - public string? ApiKey { get; set; } - - public string PaymentKey { get; set; } = Guid.NewGuid().ToString(); -} diff --git a/dist/BTCPayServer.Plugins.BreezSpark/InvoiceRecord.cs b/dist/BTCPayServer.Plugins.BreezSpark/InvoiceRecord.cs deleted file mode 100644 index d5abd9c..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/InvoiceRecord.cs +++ /dev/null @@ -1,10 +0,0 @@ -using BTCPayServer.Lightning; - -namespace BTCPayServer.Plugins.BreezSpark; - -public class InvoiceRecord -{ - public string PaymentHash { get; set; } = string.Empty; - public string Bolt11 { get; set; } = string.Empty; - public LightMoney Amount { get; set; } = LightMoney.Zero; -} diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Configure.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Configure.cshtml deleted file mode 100644 index 7f0523c..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Configure.cshtml +++ /dev/null @@ -1,44 +0,0 @@ -@using BTCPayServer -@using BTCPayServer.Abstractions.Extensions -@using BTCPayServer.Plugins.BreezSpark -@model BTCPayServer.Plugins.BreezSpark.BreezSparkSettings? -@inject BreezSparkService BreezService -@{ - ViewData.SetActivePage("Breez", "Configure", "Configure"); - var storeId = Context.GetCurrentStoreId(); - var active = (await BreezService.Get(storeId)) is not null; -} -
-
-
-
-

- @ViewData["Title"] -

-
- - @if (active) - { - - } -
-
- -
- - - - A Bitcoin 12-word mnemonic seed phrase.BACK THIS UP SAFELY! GENERATE IT RANDOMLY! SERVER ADMINS HAVE ACCESS TO THIS! - -
-
- - - - Optional. Leave blank to use the default Breez API key. -
- - -
-
-
diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Info.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Info.cshtml deleted file mode 100644 index 8fbce12..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Info.cshtml +++ /dev/null @@ -1,106 +0,0 @@ -@using Breez.Sdk.Spark -@using BTCPayServer -@using BTCPayServer.Client -@using BTCPayServer.Components.QRCode -@using BTCPayServer.Components.TruncateCenter -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Payments -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@using BTCPayServer.Services -@using BTCPayServer.Services.Invoices -@using Microsoft.AspNetCore.Mvc.TagHelpers -@using NBitcoin -@inject BreezSparkService BreezService -@inject TransactionLinkProviders TransactionLinkProviders -@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary -@{ - ViewData.SetActivePage("Breez", "Info", "Info"); - string storeId = Model switch - { - string s => s, - StoreDashboardViewModel dashboardModel => dashboardModel.StoreId, - _ => Context.GetImplicitStoreId() - }; - var sdk = BreezService.GetClient(storeId)?.Sdk; - if (sdk is null) - return; -} - -
-
-

Breez Lightning Node Information

- - @try - { - if (sdk != null) - { -
-
-
Node Status
-
-
-

- Breez Lightning Node is connected and operational. - This is a simplified view for SDK v0.4.1 compatibility. -

- -
-
-
-
Status
-
- Connected -
- -
Network
-
Bitcoin
- -
Type
-
Breez SDK v0.4.1
-
-
-
-
-
Service
-
Lightning Network
- -
Integration
-
BTCPay Server
-
-
-
-
-
- -
-
-
Quick Actions
-
- -
- } - } - catch (Exception ex) - { -
-
Node Information Unavailable
-

Unable to fetch Breez node information: @ex.Message

-

This may be due to SDK v0.4.1 compatibility changes.

-
- } -
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Logs.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Logs.cshtml deleted file mode 100644 index 3c637c1..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Logs.cshtml +++ /dev/null @@ -1,46 +0,0 @@ -@using BTCPayServer -@model System.Collections.Concurrent.ConcurrentQueue<(DateTimeOffset timestamp, string log)> -@{ - var storeId = Context.GetCurrentStoreId(); - - ViewData.SetActivePage("Breez", "Logs", "Logs"); -} - -
-
- @if (!Model.Any()) - { -

- There are no recent logs. -

- } - else - { -
- - - - - - - - - @foreach (var log in Model) - { - - - - - - - } - -
TimestampLog
- @log.timestamp.ToTimeAgo() - - @log.log -
-
- } -
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Payments.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Payments.cshtml deleted file mode 100644 index c4a6d63..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Payments.cshtml +++ /dev/null @@ -1,49 +0,0 @@ -@using BTCPayServer.Components -@using BTCPayServer -@using BTCPayServer.Abstractions.Extensions -@using BTCPayServer.Client -@using Microsoft.AspNetCore.Mvc.TagHelpers -@using BTCPayServer.Components.QRCode -@using BTCPayServer.Components.TruncateCenter -@model BTCPayServer.Plugins.BreezSpark.PaymentsViewModel -@{ - var storeId = Context.GetCurrentStoreId(); - - ViewData.SetActivePage("Breez", "Payments", "Payments"); - TempData.TryGetValue("bolt11", out var bolt11); -} - -
-
-
-

- @ViewData["Title"] -

-
- - Send - Receive -
-
- - @if (bolt11 is string bolt11s) - { -
-
- -
-
-
- - -
- - -
-
- } - - - -
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Receive.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Receive.cshtml deleted file mode 100644 index ca19652..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Receive.cshtml +++ /dev/null @@ -1,64 +0,0 @@ -@using BTCPayServer.Lightning -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@inject BreezSparkService BreezService - -@{ - ViewData.SetActivePage("Breez", "Receive", "Receive"); - var storeId = Model switch - { - string s => s, - StoreDashboardViewModel dashboardModel => dashboardModel.StoreId, - _ => Context.GetImplicitStoreId() - }; - var sdk = BreezService.GetClient(storeId)?.Sdk; - if (sdk is null) - return; - - var nodeInfo = new Breez.Sdk.Spark.GetInfoRequest(ensureSynced: false); - Breez.Sdk.Spark.GetInfoResponse? infoResponse = null; - try - { - infoResponse = await sdk.GetInfo(nodeInfo); - } - catch (Exception ex) - { - - return; - } - - var max = LightMoney.Satoshis((long)(infoResponse?.balanceSats ?? 0)); - -} - - -
-
-
-
-

- @ViewData["Title"] -

-
- - -
-
-
-
- - - Maximum receivable: @max.ToUnit(LightMoneyUnit.Satoshi) sats -
-
- - -
- -
-
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Send.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Send.cshtml deleted file mode 100644 index 315a5d2..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Send.cshtml +++ /dev/null @@ -1,100 +0,0 @@ -@using System.Numerics -@using BTCPayServer.Lightning -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@inject BreezSparkService BreezService - -@{ - ViewData.SetActivePage("Breez", "Send", "Send"); - var storeId = Model switch - { - string s => s, - StoreDashboardViewModel dashboardModel => dashboardModel.StoreId, - _ => Context.GetImplicitStoreId() - }; - var sdk = BreezService.GetClient(storeId)?.Sdk; - if (sdk is null) - return; - - var nodeInfo = new Breez.Sdk.Spark.GetInfoRequest(ensureSynced: false); - Breez.Sdk.Spark.GetInfoResponse? infoResponse = null; - try - { - infoResponse = await sdk.GetInfo(nodeInfo); - } - catch (Exception ex) - { - - return; - } - - var max = LightMoney.Satoshis((long)(infoResponse?.balanceSats ?? 0)).ToUnit(LightMoneyUnit.Satoshi); - -} - - -@if (ViewData["PaymentDetails"] is PaymentDetailsViewModel paymentDetails) -{ -
-

Payment Details

-
-
-

Destination: @paymentDetails.Destination

-

Amount: @paymentDetails.Amount sats

-
-
-

Fee: @paymentDetails.Fee sats

-

Total: @(paymentDetails.Amount + paymentDetails.Fee) sats

-
-
-
- - - - - Cancel -
-
-} -else -{ -
-
-
-
-

- @ViewData["Title"] -

-
- -
-
-
-
- - - Enter a Lightning bolt11 invoice or a Bitcoin address -
-
- - - Maximum payable: @max sats -
-
-
-
-} - -@functions { - public class PaymentDetailsViewModel - { - public string Destination { get; set; } - public long Amount { get; set; } - public long Fee { get; set; } - public string PrepareResponseJson { get; set; } - } -} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapIn.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapIn.cshtml deleted file mode 100644 index 8c8bbac..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapIn.cshtml +++ /dev/null @@ -1,212 +0,0 @@ -@using Breez.Sdk.Spark -@using BTCPayServer -@using BTCPayServer.Client -@using BTCPayServer.Components.QRCode -@using BTCPayServer.Components.TruncateCenter -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Payments -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@using BTCPayServer.Services -@using BTCPayServer.Services.Invoices -@using Microsoft.AspNetCore.Mvc.TagHelpers -@using NBitcoin -@inject BreezSparkService BreezService -@inject TransactionLinkProviders TransactionLinkProviders -@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary -@inject BTCPayNetworkProvider BTCPayNetworkProvider -@{ - ViewData.SetActivePage("Breez", "Swap In", "SwapIn"); - var pmi = PaymentMethodId.Parse("BTC-OnChain"); - string storeId = Model switch - { - string s => s, - StoreDashboardViewModel dashboardModel => dashboardModel.StoreId, - _ => Context.GetImplicitStoreId() - }; - var sdk = BreezService.GetClient(storeId)?.Sdk; - if (sdk is null) - return; - - // Get current receive payment swap info (if any) - SwapInfo? currentSwap = null; - try - { - // Simplified logic - skip complex payment lookup for now - Payment? pendingReceive = null; - - // Skip pending receive logic for SDK v0.4.1 compatibility - - // If no pending swap, create a new one - if (currentSwap == null) - { - var request = new ReceivePaymentRequest( - paymentMethod: new ReceivePaymentMethod.BitcoinAddress() - ); - var response = await sdk.ReceivePayment(request: request); - - // Create swap info from response - currentSwap = new SwapInfo - { - bitcoinAddress = response.paymentRequest, - minAllowedDeposit = 1000, // Default minimum - maxAllowedDeposit = 16777215, // Default maximum (~0.16 BTC) - status = "Created" - }; - } - } - catch (Exception ex) - { - - return; - } - - // Get refundable deposits using the new SDK pattern - // TODO: Fix for v2.2.1 - DepositInfo structure needs to be updated - // List? refundables = null; - // try - // { - // var request = new ListUnclaimedDepositsRequest(); - // var response = await sdk.ListUnclaimedDeposits(request); - // refundables = response.deposits.ToList(); - // } - // catch (Exception ex) - // { - // - // } - - @* TODO: Fix for v2.2.1 - derivation settings check needed *@ - - // NodeState API has changed in SDK v0.4.1 - using GetInfo instead - var nodeInfo = new Breez.Sdk.Spark.GetInfoRequest(ensureSynced: false); - Breez.Sdk.Spark.GetInfoResponse? ni = null; - try - { - ni = await sdk.GetInfo(nodeInfo); - } - catch (Exception ex) - { - - } - - // Use standard fee rates since RecommendedFees API may have changed - var hasFeeRates = true; // Always show fee options - - // Get explorer URL for transaction links - var network = BTCPayNetworkProvider.GetNetwork("BTC"); - var explorerUrl = network.BlockExplorerLink?.ToString() ?? "#"; -} - -@if (hasFeeRates) -{ - - - - - - - -} - -
-
- - @if (currentSwap != null) - { -
-
- -
-
-
- - -
-
- Please send an amount between
@Money.Satoshis(currentSwap.minAllowedDeposit).ToDecimal(MoneyUnit.BTC) and @Money.Satoshis(currentSwap.maxAllowedDeposit).ToDecimal(MoneyUnit.BTC)BTC
- @* TODO: Fix for v2.2.1 - derivation settings check needed *@ - @* - @if (derivationSettings != null) - { - - } - *@ -
-
-
- } - - @* - @if (refundables?.Any() is true) - { -
- - - - - - - - - - - - @foreach (var deposit in refundables) - { - - - - - - - - } - -
Deposit TxAmountSwap TxRefundableActions
- @{ - var txLink = TransactionLinkProviders.GetTransactionLink(deposit.txId, "BTC"); - } - - - - @deposit.amount - @if (!string.IsNullOrEmpty(deposit.swapTxId)) - { - var swapTxLink = TransactionLinkProviders.GetTransactionLink(deposit.swapTxId, "BTC"); - - - - } - else - { - N/A - } - - @if (deposit.refundable) - { - Yes - } - else - { - No - } - -
- -
-
-
- } - *@ -
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapInRefund.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapInRefund.cshtml deleted file mode 100644 index eafd0de..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapInRefund.cshtml +++ /dev/null @@ -1,73 +0,0 @@ -@using BTCPayServer -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@using BTCPayServer.Services.Invoices -@using Microsoft.AspNetCore.Mvc.TagHelpers -@using Microsoft.AspNetCore.Routing -@model string -@inject BreezSparkService BreezService -@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary -@* @inject BTCPayNetworkProvider BTCPayNetworkProvider *@ -@{ - var storeId = Context.GetImplicitStoreId(); - var address = Context.GetRouteValue("address").ToString(); - ViewData.SetActivePage("Breez", "Create Swapin Refund", "SwapIn"); - - @* TODO: Fix for v2.2.1 - derivation settings check needed *@ - var sdk = BreezService.GetClient(storeId)?.Sdk; - // Use standard fee rates since RecommendedFees API may have changed - var standardFees = new { fastestFee = 10, halfHourFee = 5, hourFee = 3, economyFee = 2, minimumFee = 1 }; -} - - - - - - - - - -@* - @if (derivationSettings is not null) - { - - } -*@ - - -
-
-
-
-

- @ViewData["Title"] - - - -

-
- -
-
-
-
- - -
-
- - -
-
- - -
-
- - - Choose from preset fee rates or enter custom value -
- -
-
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapOut.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapOut.cshtml deleted file mode 100644 index be48c79..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/SwapOut.cshtml +++ /dev/null @@ -1,83 +0,0 @@ -@using Breez.Sdk.Spark -@using BTCPayServer -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@using BTCPayServer.Services.Invoices -@using Microsoft.AspNetCore.Mvc.TagHelpers -@inject BreezSparkService BreezService -@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary -@* @inject BTCPayNetworkProvider BTCPayNetworkProvider *@ -@{ - Layout = "_Layout"; - ViewData.SetActivePage("Breez", "Swap Out", "SwapOut"); - string storeId = null; - if (Model is string s) - { - storeId = s; - } - else if (Model is StoreDashboardViewModel dashboardModel) - { - storeId = dashboardModel.StoreId; - } - else - { - storeId = Context.GetImplicitStoreId(); - } - - // Simplified fee structure for SDK v0.4.1 compatibility - var fastFee = 10; - var slowFee = 5; - var minFee = 1; -} - - - - - - - - - - - @{ - @* TODO: Fix derivation settings for v2.2.1 - GetDerivationSchemeSettings method signature changed *@ - var hasStoreWallet = false; - if (hasStoreWallet) - { - - } - } - - -
-
-
-
-

- @ViewData["Title"] -

-
- -
-
-
-
- - -
-
- - - Choose from preset fee rates or enter custom value -
-
- - -

Minimum: 1000 sats, Maximum: 10000000 sats

-
- - -
-
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Sweep.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Sweep.cshtml deleted file mode 100644 index dbed979..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/Sweep.cshtml +++ /dev/null @@ -1,79 +0,0 @@ -@using BTCPayServer -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@using BTCPayServer.Services.Invoices -@using Microsoft.AspNetCore.Mvc.TagHelpers -@inject BreezSparkService BreezService -@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary -@* @inject BTCPayNetworkProvider BTCPayNetworkProvider *@ -@{ - Layout = "_Layout"; - ViewData.SetActivePage("Breez", "Sweep", "Sweep"); - string storeId = null; - if (Model is string s) - { - storeId = s; - } - else if (Model is StoreDashboardViewModel dashboardModel) - { - storeId = dashboardModel.StoreId; - } - else - { - storeId = Context.GetImplicitStoreId(); - } - var sdk = BreezService.GetClient(storeId)?.Sdk; - if (sdk is null) - return; - - @* TODO: Fix for v2.2.1 - derivation settings check needed *@ - // Use standard fee rates since RecommendedFees API may have changed - var standardFees = new { fastestFee = 10, halfHourFee = 5, hourFee = 3, economyFee = 2, minimumFee = 1 }; -} - - - - - - - - - -@* - @if (derivationSettings is not null) - { - - } -*@ - - -
-
-
-
-

- @ViewData["Title"] - - - -

-
- -
-
-
-
- - - Address to sweep funds to -
-
- - - Choose from preset fee rates or enter custom value -
- -
-
-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/_Nav.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/BreezSpark/_Nav.cshtml deleted file mode 100644 index e69de29..0000000 diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezNodeInfo.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezNodeInfo.cshtml deleted file mode 100644 index e4e80ab..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezNodeInfo.cshtml +++ /dev/null @@ -1,90 +0,0 @@ -@using BTCPayServer.Lightning -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@using BTCPayServer.Client -@inject BreezSparkService BreezService -@{ - string storeId = null; - if (Model is string s) - { - storeId = s; - } - else if (Model is StoreDashboardViewModel dashboardModel) - { - storeId = dashboardModel.StoreId; - } - else - { - storeId = Context.GetImplicitStoreId(); - } - - // In SDK v0.4.1, NodeState API has changed and async calls can't be made from partial views - // This widget needs to be refactored to receive data from controller - bool isConfigured = false; - try - { - var client = BreezService.GetClient(storeId); - isConfigured = client?.Sdk != null; - } - catch - { - // Handle any errors gracefully - } -} - - -
- @if (Model is StoreDashboardViewModel) - { -
-

Breez Node

- - Manage - - -
- } - - @if (isConfigured) - { -
- -
Breez Spark (nodeless)
-
- -
-
-
Lightning Balance
- @if (Model is StoreDashboardViewModel) - { -
- Swap In - Send -
- } -
-
- Dashboard widget updated for SDK v0.4.1 -
-
- } - else - { -
-

Breez node information not available

- @if (string.IsNullOrEmpty(storeId)) - { - Configure Breez - } -
- } -
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezPaymentsTable.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezPaymentsTable.cshtml deleted file mode 100644 index feed480..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezPaymentsTable.cshtml +++ /dev/null @@ -1,94 +0,0 @@ -@using Breez.Sdk.Spark -@using BTCPayServer.Lightning -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@model List -@{ - var data = Model ?? new List(); - var storeId = Context.GetImplicitStoreId(); - if (data is null) - { - if (string.IsNullOrEmpty(storeId)) - return; - } - - var isDashboard = false; -} -@if (isDashboard) -{ - -} -
- @if (isDashboard) - { -
-

Breez Payments

- @if (data.Any()) - { - View All - } -
- } - @if (!data.Any()) - { -

- There are no recent payments. -

- } - else - { -
- - - - - - - - - - - - - - @foreach (var payment in data) - { - - - - - - - - - - - } - -
IdTimestampTypeAmountFeeStatusDescription
- - @payment.Id - - - @DateTimeOffset.FromUnixTimeSeconds((long)payment.Timestamp).ToTimeAgo() ?? "Unknown" - - @(payment.PaymentType == PaymentType.Receive ? "receive" : "send") - - @payment.Amount.ToDecimal(LightMoneyUnit.BTC) BTC - - @payment.Fee.ToDecimal(LightMoneyUnit.BTC) BTC - - @payment.Status.ToString().ToLowerInvariant() - - @payment.Description -
-
- } -
diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezSparkNav.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezSparkNav.cshtml deleted file mode 100644 index dd59361..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/BreezSparkNav.cshtml +++ /dev/null @@ -1,60 +0,0 @@ -@using Breez.Sdk -@using BTCPayServer.Abstractions.Contracts -@using BTCPayServer.Abstractions.Extensions -@using BTCPayServer.Client -@using BTCPayServer.Models.StoreViewModels -@using BTCPayServer.Plugins.BreezSpark -@using BTCPayServer.Security -@using Microsoft.AspNetCore.Mvc.TagHelpers -@inject IScopeProvider ScopeProvider -@inject BreezSparkService BreezService -@{ - var storeId = Model switch - { - string s => s, - StoreDashboardViewModel dashboardModel => dashboardModel.StoreId, - _ => Context.GetImplicitStoreId() - }; - var active = @ViewData.IsActivePage("Breez"); - var client = string.IsNullOrEmpty(active) ? null : BreezService.GetClient(storeId); - var sdk = client?.Sdk; -} -@if (!string.IsNullOrEmpty(storeId)) -{ - - - @if (sdk is not null) - { - - - - @if (client.Events.Any()) - { - - } - } -} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/LNPaymentMethodSetupTab.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/LNPaymentMethodSetupTab.cshtml deleted file mode 100644 index c65d51f..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/LNPaymentMethodSetupTab.cshtml +++ /dev/null @@ -1,90 +0,0 @@ -@model BTCPayServer.Models.StoreViewModels.LightningNodeViewModel -@inject BreezSparkService BreezService -@{ - var storeId = Model.StoreId; - if (Model.CryptoCode != "BTC") - { - return; - } - - // Try to get existing Breez client to extract the payment key - var breezClient = BreezService.GetClient(Model.StoreId); - string paymentKey = ""; - - if (breezClient != null) - { - // Extract payment key from the existing client connection string - var connStr = breezClient.ToString(); - if (connStr.Contains("key=")) - { - var keyStart = connStr.IndexOf("key=") + 4; - var keyEnd = connStr.IndexOf(";", keyStart); - if (keyEnd == -1) keyEnd = connStr.Length; - paymentKey = connStr.Substring(keyStart, keyEnd - keyStart); - } - } -} - - - - - -
-

You can use Breez to accept lightning payments without running a traditional Lightning node.

-

Breez is a mobile-first Lightning Network client that provides a non-custodial solution for Lightning payments.

-
\ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/LNPaymentMethodSetupTabhead.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/LNPaymentMethodSetupTabhead.cshtml deleted file mode 100644 index 375a4f7..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/Shared/BreezSpark/LNPaymentMethodSetupTabhead.cshtml +++ /dev/null @@ -1,38 +0,0 @@ -@inject BreezSparkService BreezService; -@using BTCPayServer.Client -@using BTCPayServer.Plugins.BreezSpark -@using Microsoft.AspNetCore.Mvc.TagHelpers -@model BTCPayServer.Models.StoreViewModels.LightningNodeViewModel - -@if (Model.CryptoCode != "BTC") -{ - return; -} - -@{ - var breezClient = BreezService.GetClient(Model.StoreId); -} - -@if (breezClient == null) -{ - - - -} -else -{ - - - -} \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/Views/_ViewImports.cshtml b/dist/BTCPayServer.Plugins.BreezSpark/Views/_ViewImports.cshtml deleted file mode 100644 index ee5ced0..0000000 --- a/dist/BTCPayServer.Plugins.BreezSpark/Views/_ViewImports.cshtml +++ /dev/null @@ -1,9 +0,0 @@ -@using BTCPayServer.Abstractions.Extensions -@using BTCPayServer.Plugins.BreezSpark -@using Breez.Sdk.Spark -@inject BTCPayServer.Abstractions.Services.Safe Safe -@addTagHelper *, BTCPayServer.Abstractions -@addTagHelper *, BTCPayServer.TagHelpers -@addTagHelper *, BTCPayServer.Views.TagHelpers -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@addTagHelper *, BTCPayServer \ No newline at end of file diff --git a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so b/dist/BTCPayServer.Plugins.BreezSpark/runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so deleted file mode 100755 index 4cb9b94..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so b/dist/BTCPayServer.Plugins.BreezSpark/runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so deleted file mode 100755 index 33401a5..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib b/dist/BTCPayServer.Plugins.BreezSpark/runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib deleted file mode 100755 index 00b9053..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib b/dist/BTCPayServer.Plugins.BreezSpark/runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib deleted file mode 100755 index dbe3dff..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/win-x64/native/breez_sdk_spark_bindings.dll b/dist/BTCPayServer.Plugins.BreezSpark/runtimes/win-x64/native/breez_sdk_spark_bindings.dll deleted file mode 100755 index f18d5f3..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/win-x64/native/breez_sdk_spark_bindings.dll and /dev/null differ diff --git a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/win-x86/native/breez_sdk_spark_bindings.dll b/dist/BTCPayServer.Plugins.BreezSpark/runtimes/win-x86/native/breez_sdk_spark_bindings.dll deleted file mode 100755 index 1dd2e31..0000000 Binary files a/dist/BTCPayServer.Plugins.BreezSpark/runtimes/win-x86/native/breez_sdk_spark_bindings.dll and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.deps.json b/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.deps.json deleted file mode 100644 index 3b924af..0000000 --- a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.deps.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETCoreApp,Version=v8.0", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETCoreApp,Version=v8.0": { - "BTCPayServer.Plugins.BreezSpark/1.1.0": { - "dependencies": { - "Breez.Sdk.Spark": "0.4.1" - }, - "runtime": { - "BTCPayServer.Plugins.BreezSpark.dll": {} - } - }, - "Breez.Sdk.Spark/0.4.1": { - "runtime": { - "lib/net8.0/Breez.Sdk.Spark.dll": { - "assemblyVersion": "0.4.1.0", - "fileVersion": "0.4.1.0" - } - }, - "runtimeTargets": { - "runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so": { - "rid": "linux-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib": { - "rid": "osx-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib": { - "rid": "osx-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x64/native/breez_sdk_spark_bindings.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x86/native/breez_sdk_spark_bindings.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "0.0.0.0" - } - } - } - } - }, - "libraries": { - "BTCPayServer.Plugins.BreezSpark/1.1.0": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Breez.Sdk.Spark/0.4.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-/5iC7V3PK0q5og4h5qnSf5xepfvcXSEeV5WJDIAlOGd7WUtMZdNQ0n6yDcgd1Rv5qcxPQsDGQN3IVQZbP0UE1w==", - "path": "breez.sdk.spark/0.4.1", - "hashPath": "breez.sdk.spark.0.4.1.nupkg.sha512" - } - } -} \ No newline at end of file diff --git a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.dll b/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.dll deleted file mode 100644 index 79beade..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.dll and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.pdb b/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.pdb deleted file mode 100644 index 89f1b9b..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.pdb and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.staticwebassets.endpoints.json b/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.staticwebassets.endpoints.json deleted file mode 100644 index 21da96b..0000000 --- a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.staticwebassets.endpoints.json +++ /dev/null @@ -1 +0,0 @@ -{"Version":1,"ManifestType":"Publish","Endpoints":[]} \ No newline at end of file diff --git a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.xml b/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.xml deleted file mode 100644 index 25320e3..0000000 --- a/published/BTCPayServer.Plugins.BreezSpark/BTCPayServer.Plugins.BreezSpark.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - BTCPayServer.Plugins.BreezSpark - - - - diff --git a/published/BTCPayServer.Plugins.BreezSpark/Breez.Sdk.Spark.dll b/published/BTCPayServer.Plugins.BreezSpark/Breez.Sdk.Spark.dll deleted file mode 100755 index 7db16f5..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/Breez.Sdk.Spark.dll and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so b/published/BTCPayServer.Plugins.BreezSpark/runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so deleted file mode 100755 index 4cb9b94..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/runtimes/linux-arm64/native/libbreez_sdk_spark_bindings.so and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so b/published/BTCPayServer.Plugins.BreezSpark/runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so deleted file mode 100755 index 33401a5..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/runtimes/linux-x64/native/libbreez_sdk_spark_bindings.so and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib b/published/BTCPayServer.Plugins.BreezSpark/runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib deleted file mode 100755 index 00b9053..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/runtimes/osx-arm64/native/libbreez_sdk_spark_bindings.dylib and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib b/published/BTCPayServer.Plugins.BreezSpark/runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib deleted file mode 100755 index dbe3dff..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/runtimes/osx-x64/native/libbreez_sdk_spark_bindings.dylib and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/runtimes/win-x64/native/breez_sdk_spark_bindings.dll b/published/BTCPayServer.Plugins.BreezSpark/runtimes/win-x64/native/breez_sdk_spark_bindings.dll deleted file mode 100755 index f18d5f3..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/runtimes/win-x64/native/breez_sdk_spark_bindings.dll and /dev/null differ diff --git a/published/BTCPayServer.Plugins.BreezSpark/runtimes/win-x86/native/breez_sdk_spark_bindings.dll b/published/BTCPayServer.Plugins.BreezSpark/runtimes/win-x86/native/breez_sdk_spark_bindings.dll deleted file mode 100755 index 1dd2e31..0000000 Binary files a/published/BTCPayServer.Plugins.BreezSpark/runtimes/win-x86/native/breez_sdk_spark_bindings.dll and /dev/null differ