From 5f62988f01f324a53f0a1bdcd7c982d301b76846 Mon Sep 17 00:00:00 2001 From: Kukks Date: Thu, 7 Dec 2023 10:50:10 +0100 Subject: [PATCH] fix breez and add blink --- .../BTCPayServer.Plugins.Blink.csproj | 47 ++ .../BlinkLightningClient.cs | 645 ++++++++++++++++++ .../BlinkLightningConnectionStringHandler.cs | 91 +++ .../BTCPayServer.Plugins.Blink/BlinkPlugin.cs | 29 + .../Blink/LNPaymentMethodSetupTab.cshtml | 39 ++ .../Views/_ViewImports.cshtml | 9 + .../BTCPayServer.Plugins.Breez.csproj | 7 +- .../BreezController.cs | 2 +- .../BreezLightningClient.cs | 5 +- .../Views/Breez/SwapIn.cshtml | 13 +- .../Shared/Breez/BreezPaymentsTable.cshtml | 2 +- .../BTCPayServer.Plugins.Wabisabi.csproj | 2 +- 12 files changed, 876 insertions(+), 15 deletions(-) create mode 100644 Plugins/BTCPayServer.Plugins.Blink/BTCPayServer.Plugins.Blink.csproj create mode 100644 Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs create mode 100644 Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs create mode 100644 Plugins/BTCPayServer.Plugins.Blink/BlinkPlugin.cs create mode 100644 Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml create mode 100644 Plugins/BTCPayServer.Plugins.Blink/Views/_ViewImports.cshtml diff --git a/Plugins/BTCPayServer.Plugins.Blink/BTCPayServer.Plugins.Blink.csproj b/Plugins/BTCPayServer.Plugins.Blink/BTCPayServer.Plugins.Blink.csproj new file mode 100644 index 0000000..90a4bb8 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Blink/BTCPayServer.Plugins.Blink.csproj @@ -0,0 +1,47 @@ + + + + net8.0 + 10 + + + + + Blink + Brink Lightning support + 1.0.0 + BTCPayServer.Plugins.Blink + + + + true + false + true + + + + + + StaticWebAssetsEnabled=false + false + runtime;native;build;buildTransitive;contentFiles + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs new file mode 100644 index 0000000..786a453 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs @@ -0,0 +1,645 @@ +#nullable enable +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using BTCPayServer.HostedServices; +using BTCPayServer.Lightning; +using BTCPayServer.Lightning.LndHub; +using GraphQL; +using GraphQL.Client.Http; +using GraphQL.Client.Serializer.Newtonsoft; +using NBitcoin; +using NBitpayClient; +using Newtonsoft.Json.Linq; +using Network = NBitcoin.Network; + +namespace BTCPayServer.Plugins.Blink; + +public class BlinkLightningClient : ILightningClient +{ + private readonly string _apiKey; + private readonly Uri _apiEndpoint; + private readonly string _walletId; + private readonly Network _network; + private readonly NBXplorerDashboard _nbXplorerDashboard; + private readonly GraphQLHttpClient _client; + + public BlinkLightningClient(string apiKey, Uri apiEndpoint, string walletId, Network network, + NBXplorerDashboard nbXplorerDashboard, HttpClient httpClient) + { + _apiKey = apiKey; + _apiEndpoint = apiEndpoint; + _walletId = walletId; + _network = network; + _nbXplorerDashboard = nbXplorerDashboard; + _client = new GraphQLHttpClient(new GraphQLHttpClientOptions() {EndPoint = _apiEndpoint}, new NewtonsoftJsonSerializer(), httpClient); + } + + public override string ToString() + { + return $"type=blink;server={_apiEndpoint};api-key={_apiKey};wallet-id={_walletId}"; + } + + public async Task GetInvoice(string invoiceId, + CancellationToken cancellation = new CancellationToken()) + { + + var reques = new GraphQLRequest + { + Query = @" +query InvoiceByPaymentHash($paymentHash: PaymentHash!, $walletId: WalletId!) { + me { + defaultAccount { + walletById(walletId: $walletId) { + invoiceByPaymentHash(paymentHash: $paymentHash) { + createdAt + paymentHash + paymentRequest + paymentSecret + paymentStatus + } + } + } + } +}", + OperationName = "InvoiceByPaymentHash", + Variables = new + { + walletId = _walletId, + paymentHash = invoiceId + } + }; + var response = await _client.SendQueryAsync(reques, cancellation); + + + return response.Data is null ? null : ToInvoice(response.Data.me.defaultAccount.walletById.invoiceByPaymentHash); + } + + public LightningInvoice? ToInvoice(JObject invoice) + { + var bolt11 = BOLT11PaymentRequest.Parse(invoice["paymentRequest"].Value(), _network); + return new LightningInvoice() + { + Id = invoice["paymentHash"].Value(), + Amount = invoice["satoshis"] is null? bolt11.MinimumAmount: LightMoney.Satoshis(invoice["satoshis"].Value()), + Preimage = invoice["paymentSecret"].Value(), + PaidAt = (invoice["paymentStatus"].Value()) == "PAID"? DateTimeOffset.UtcNow : null, + Status = (invoice["paymentStatus"].Value()) switch + { + "EXPIRED" => LightningInvoiceStatus.Expired, + "PAID" => LightningInvoiceStatus.Paid, + "PENDING" => LightningInvoiceStatus.Unpaid + }, + BOLT11 = invoice["paymentRequest"].Value(), + PaymentHash = invoice["paymentHash"].Value(), + ExpiresAt = bolt11.ExpiryDate + }; + } + + public async Task GetInvoice(uint256 paymentHash, + CancellationToken cancellation = new CancellationToken()) + { + return await GetInvoice(paymentHash.ToString(), cancellation); + } + + public async Task ListInvoices(CancellationToken cancellation = new CancellationToken()) + { + return await ListInvoices(new ListInvoicesParams(), cancellation); + } + + public async Task ListInvoices(ListInvoicesParams request, + CancellationToken cancellation = new CancellationToken()) + { + var reques = new GraphQLRequest + { + Query = @" +query Invoices($walletId: WalletId!) { + me { + defaultAccount { + walletById(walletId: $walletId) { + invoices { + edges { + node { + createdAt + paymentHash + paymentRequest + paymentSecret + paymentStatus + ... on LnInvoice { + satoshis + } + } + } + } + } + } + } +}", + OperationName = "Invoices", + Variables = new + { + walletId = _walletId + } + }; + var response = await _client.SendQueryAsync(reques, cancellation); + + var result = ((JArray)response.Data.me.defaultAccount.walletById.invoices.edges).Select(o => ToInvoice((JObject) o["node"] )).Where(o => o is not null || request.PendingOnly is not true || o.Status == LightningInvoiceStatus.Unpaid).ToArray(); + return (LightningInvoice[]) result; + } + + public async Task GetPayment(string paymentHash, + CancellationToken cancellation = new CancellationToken()) + { + var reques = new GraphQLRequest + { + Query = @" +query TransactionsByPaymentHash($paymentHash: PaymentHash!, $walletId: WalletId!) { + me { + defaultAccount { + walletById(walletId: $walletId) { + transactionsByPaymentHash(paymentHash: $paymentHash) { + createdAt + direction + id + initiationVia { + ... on InitiationViaLn { + paymentHash + paymentRequest + } + } + memo + settlementAmount + settlementCurrency + settlementVia { + ... on SettlementViaLn { + preImage + } + } + status + } + } + } + } +}", + OperationName = "TransactionsByPaymentHash", + Variables = new + { + walletId = _walletId, + paymentHash = paymentHash + } + }; + var response = await _client.SendQueryAsync(reques, cancellation); + var item = (JArray) response.Data.me.defaultAccount.walletById.transactionsByPaymentHash; + return item.Any()? ToLightningPayment((JObject)item.First()): null; + } + + public LightningPayment? ToLightningPayment(JObject transaction) + { + if ((string)transaction["direction"] == "RECEIVE") + return null; + + var initiationVia = transaction["initiationVia"]; + if (initiationVia["paymentHash"] == null) + return null; + + var bolt11 = BOLT11PaymentRequest.Parse((string)initiationVia["paymentRequest"], _network); + + return new LightningPayment() + { + Amount = bolt11.MinimumAmount, + Status = transaction["status"].ToString() switch + { + "FAILURE" => LightningPaymentStatus.Failed, + "PENDING" => LightningPaymentStatus.Pending, + "SUCCESS" => LightningPaymentStatus.Complete, + _ => LightningPaymentStatus.Unknown + }, + BOLT11 = (string)initiationVia["paymentRequest"], + Id = (string)initiationVia["paymentHash"], + PaymentHash = (string)initiationVia["paymentHash"], + CreatedAt = DateTimeOffset.FromUnixTimeSeconds(transaction["createdAt"].Value()), + AmountSent = bolt11.MinimumAmount, + }; + } + + public async Task ListPayments(CancellationToken cancellation = new CancellationToken()) + { + return await ListPayments(new ListPaymentsParams(), cancellation); + } + + public async Task ListPayments(ListPaymentsParams request, + CancellationToken cancellation = new CancellationToken()) + { + + var reques = new GraphQLRequest + { + Query = @" +query Transactions($walletId: WalletId!) { + me { + defaultAccount { + walletById(walletId: $walletId) { + transactions { + edges { + node { + createdAt + direction + id + initiationVia { + ... on InitiationViaLn { + paymentHash + paymentRequest + } + } + memo + settlementAmount + settlementCurrency + settlementVia { + ... on SettlementViaLn { + preImage + } + } + status + } + } + } + } + } + } +}", + OperationName = "Transactions", + Variables = new + { + walletId = _walletId + } + }; + var response = await _client.SendQueryAsync(reques, cancellation); + + + + var result = ((JArray)response.Data.me.defaultAccount.walletById.transactions.edges).Select(o => ToLightningPayment((JObject) o["node"])).Where(o => o is not null && (request.IncludePending is not true || o.Status!= LightningPaymentStatus.Pending)).ToArray(); + return (LightningPayment[]) result; + } + + public async Task CreateInvoice(LightMoney amount, string description, TimeSpan expiry, + CancellationToken cancellation = new()) + { + return await CreateInvoice(new CreateInvoiceParams(amount, description, expiry), cancellation); + } + + public async Task CreateInvoice(CreateInvoiceParams createInvoiceRequest, + CancellationToken cancellation = new()) + { + var reques = new GraphQLRequest + { + Query = @" +mutation LnInvoiceCreate($input: LnInvoiceCreateInput!) { + lnInvoiceCreate(input: $input) { + invoice { + createdAt + paymentHash + paymentRequest + paymentSecret + paymentStatus + satoshis + + } + } +}", + OperationName = "LnInvoiceCreate", + Variables = new + { + input = new + { + walletId = _walletId, + memo = createInvoiceRequest.Description?? createInvoiceRequest.DescriptionHash?.ToString(), + amount = (long)createInvoiceRequest.Amount.ToUnit(LightMoneyUnit.Satoshi), +expiresIn = (int)createInvoiceRequest.Expiry.TotalMinutes + + } + } + }; + var response = await _client.SendQueryAsync(reques, cancellation); + + + return ToInvoice(response.Data.lnInvoiceCreate.invoice); + } + + public async Task Listen(CancellationToken cancellation = new CancellationToken()) + { + return new BlinkListener(this, cancellation); + } + + + public class BlinkListener : ILightningInvoiceListener + { + private readonly ILightningClient _client; + private readonly Channel _invoices = Channel.CreateUnbounded(); + private readonly CancellationTokenSource _cts; + private HttpClient _httpClient; + private HttpResponseMessage _response; + private Stream _body; + private StreamReader _reader; + private Task _listenLoop; + private readonly List _paidInvoiceIds; + + public BlinkListener(ILightningClient client, CancellationToken cancellation) + { + _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellation); + _client = client; + _paidInvoiceIds = new List(); + _listenLoop = ListenLoop(); + } + + public async Task WaitInvoice(CancellationToken cancellation) + { + try + { + return await _invoices.Reader.ReadAsync(cancellation); + } + catch (ChannelClosedException ex) when (ex.InnerException == null) + { + throw new OperationCanceledException(); + } + catch (ChannelClosedException ex) + { + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + throw; + } + } + + public void Dispose() + { + Dispose(true); + } + + static readonly AsyncDuplicateLock _locker = new(); + static readonly ConcurrentDictionary _activeListeners = new(); + + private async Task ListenLoop() + { + try + { + var releaser = await _locker.LockOrBustAsync(_client.ToString(), _cts.Token); + if (releaser is null) + { + while (!_cts.IsCancellationRequested && releaser is null) + { + if (_activeListeners.TryGetValue(_client.ToString(), out var invoicesData)) + { + await HandleInvoicesData(invoicesData); + } + + releaser = await _locker.LockOrBustAsync(_client.ToString(), _cts.Token); + + if (releaser is null) + await Task.Delay(2500, _cts.Token); + } + } + + using (releaser) + { + while (!_cts.IsCancellationRequested) + { + var invoicesData = await _client.ListInvoices(_cts.Token); + _activeListeners.AddOrReplace(_client.ToString(), invoicesData); + await HandleInvoicesData(invoicesData); + + await Task.Delay(2500, _cts.Token); + } + } + } + catch when (_cts.IsCancellationRequested) + { + } + catch (Exception ex) + { + _invoices.Writer.TryComplete(ex); + } + finally + { + _activeListeners.TryRemove(_client.ToString(), out _); + Dispose(false); + } + } + + private async Task HandleInvoicesData(IEnumerable invoicesData) + { + foreach (var data in invoicesData) + { + var invoice = data; + if (invoice.PaidAt != null && !_paidInvoiceIds.Contains(invoice.Id)) + { + await _invoices.Writer.WriteAsync(invoice, _cts.Token); + _paidInvoiceIds.Add(invoice.Id); + } + } + } + + private void Dispose(bool waitLoop) + { + if (_cts.IsCancellationRequested) + return; + _cts.Cancel(); + _reader?.Dispose(); + _reader = null; + _body?.Dispose(); + _body = null; + _response?.Dispose(); + _response = null; + _httpClient?.Dispose(); + _httpClient = null; + if (waitLoop) + _listenLoop?.Wait(); + _invoices.Writer.TryComplete(); + } + } + + public async Task GetInfo(CancellationToken cancellation = new CancellationToken()) + { + + var reques = new GraphQLRequest + { + Query = @" +query Globals { + globals { + nodesIds + } +}", + OperationName = "Globals" + }; + var response = await _client.SendQueryAsync(reques, cancellation); + var result = new LightningNodeInformation() + { + BlockHeight = _nbXplorerDashboard.Get("BTC").Status.ChainHeight, + Alias = "Blink", + + }; + result.NodeInfoList.AddRange(((JArray)response.Data.globals.nodesIds).Select(s => new NodeInfo(new PubKey(s.Value()), "galoy.com", 69))); + return result; + } + + public async Task GetBalance(CancellationToken cancellation = new()) + { + var request = new GraphQLRequest + { + Query = @" +query GetWallet($walletId: WalletId!) { + me { + defaultAccount { + walletById(walletId: $walletId) { + id + balance + walletCurrency + } + } + } +}", + OperationName = "GetWallet", + Variables = new { + walletId = _walletId + } + }; + + var response = await _client.SendQueryAsync(request, cancellation); + + if (response.Data.me.defaultAccount.walletById.walletCurrency == "BTC") + { + return new LightningNodeBalance() + { + OffchainBalance = new OffchainBalance() + { + Local = LightMoney.Satoshis((long)response.Data.me.defaultAccount.walletById.balance) + } + }; + } + + return new LightningNodeBalance(); + } + + + + public async Task Pay(PayInvoiceParams payParams, + CancellationToken cancellation = new CancellationToken()) + { + return await Pay(null, new PayInvoiceParams(), cancellation); + } + + public async Task Pay(string bolt11, PayInvoiceParams payParams, + CancellationToken cancellation = new CancellationToken()) + { + + var request = new GraphQLRequest + { + Query = @" +mutation LnInvoicePaymentSend($input: LnInvoicePaymentInput!) { + lnInvoicePaymentSend(input: $input) { + transaction { + createdAt + direction + id + initiationVia { + ... on InitiationViaLn { + paymentHash + paymentRequest + } + } + memo + settlementAmount + settlementCurrency + settlementVia { + ... on SettlementViaLn { + preImage + } + } + status + } + errors { + message + } + status + } +}", + OperationName = "LnInvoicePaymentSend", + Variables = new { + input = new { + walletId = _walletId, + paymentRequest = bolt11, + } + } + }; + CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellation, + new CancellationTokenSource(payParams?.SendTimeout ?? PayInvoiceParams.DefaultSendTimeout).Token); + var response =(JObject) (await _client.SendQueryAsync(request, cts.Token)).Data.lnInvoicePaymentSend; + + var result = new PayResponse(); + result.Result = response["status"].Value() switch + { + "ALREADY_PAID" => PayResult.Ok, + "FAILURE" => PayResult.Error, + "PENDING"=> PayResult.Unknown, + "SUCCESS" => PayResult.Ok, + null => PayResult.Unknown, + _ => throw new ArgumentOutOfRangeException() + }; + if (response["transaction"]?.Value() is not null) + { + result.Details = new PayDetails() + { + PaymentHash = new uint256(response["transaction"]["initiationVia"]["paymentHash"].Value()), + Status = response["status"].Value() switch + { + "ALREADY_PAID" => LightningPaymentStatus.Complete, + "FAILURE" => LightningPaymentStatus.Failed, + "PENDING" => LightningPaymentStatus.Pending, + "SUCCESS" => LightningPaymentStatus.Complete, + null => LightningPaymentStatus.Unknown, + _ => throw new ArgumentOutOfRangeException() + }, + Preimage = response["transaction"]["settlementVia"]?["preImage"].Value() is null? null: new uint256(response["transaction"]["settlementVia"]["preImage"].Value()), + }; + } + + return result; + } + + public async Task Pay(string bolt11, CancellationToken cancellation = new CancellationToken()) + { + return await Pay(bolt11, new PayInvoiceParams(), cancellation); + } + + + public async Task CancelInvoice(string invoiceId, CancellationToken cancellation = new CancellationToken()) + { + throw new NotImplementedException(); + } + + public async Task GetDepositAddress(CancellationToken cancellation = new CancellationToken()) + { + throw new NotImplementedException(); + } + + public async Task OpenChannel(OpenChannelRequest openChannelRequest, + CancellationToken cancellation = new CancellationToken()) + { + throw new NotImplementedException(); + } + + public async Task ConnectTo(NodeInfo nodeInfo, + CancellationToken cancellation = new CancellationToken()) + { + throw new NotImplementedException(); + } + + public async Task ListChannels(CancellationToken cancellation = new CancellationToken()) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs new file mode 100644 index 0000000..1f07b32 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs @@ -0,0 +1,91 @@ +#nullable enable +using System; +using System.Linq; +using System.Net.Http; +using BTCPayServer.HostedServices; +using BTCPayServer.Lightning; +using Network = NBitcoin.Network; + +namespace BTCPayServer.Plugins.Blink; + + +public class BlinkLightningConnectionStringHandler : ILightningConnectionStringHandler +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly NBXplorerDashboard _nbXplorerDashboard; + + public BlinkLightningConnectionStringHandler(IHttpClientFactory httpClientFactory, NBXplorerDashboard nbXplorerDashboard) + { + _httpClientFactory = httpClientFactory; + _nbXplorerDashboard = nbXplorerDashboard; + } + + + public ILightningClient? Create(string connectionString, Network network, out string? error) + { + var kv = LightningConnectionStringHelper.ExtractValues(connectionString, out var type); + if (type != "blink") + { + error = null; + return null; + } + if (!kv.TryGetValue("server", out var server)) + { + error = $"The key 'server' is mandatory for blink connection strings"; + return null; + } + if (!Uri.TryCreate(server, UriKind.Absolute, out var uri) + || uri.Scheme != "http" && uri.Scheme != "https") + { + error = "The key 'server' should be an URI starting by http:// or https://"; + return null; + } + bool allowInsecure = false; + if (kv.TryGetValue("allowinsecure", out var allowinsecureStr)) + { + var allowedValues = new[] {"true", "false"}; + if (!allowedValues.Any(v => v.Equals(allowinsecureStr, StringComparison.OrdinalIgnoreCase))) + { + error = "The key 'allowinsecure' should be true or false"; + return null; + } + + allowInsecure = allowinsecureStr.Equals("true", StringComparison.OrdinalIgnoreCase); + } + + if (!LightningConnectionStringHelper.VerifySecureEndpoint(uri, allowInsecure)) + { + error = "The key 'allowinsecure' is false, but server's Uri is not using https"; + return null; + } + if (!kv.TryGetValue("api-key", out var apiKey)) + { + error = "The key 'api-key' is not found"; + return null; + } + if (!kv.TryGetValue("wallet-id", out var walletId)) + { + error = "The key 'wallet-id' is not found"; + return null; + } + + error = null; + + var client = _httpClientFactory.CreateClient(); + + client.DefaultRequestHeaders.Add("X-Api-Key", apiKey); + + client.BaseAddress = uri; + + network = Network.Main; + var bclient = new BlinkLightningClient( apiKey, uri, walletId, network, _nbXplorerDashboard, client); + var result = bclient.GetBalance().GetAwaiter().GetResult(); + if (result is null) + { + error = "Invalid credentials"; + return null; + } + return bclient; + + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Blink/BlinkPlugin.cs b/Plugins/BTCPayServer.Plugins.Blink/BlinkPlugin.cs new file mode 100644 index 0000000..d5756b8 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Blink/BlinkPlugin.cs @@ -0,0 +1,29 @@ +#nullable enable +using BTCPayServer.Abstractions.Contracts; +using BTCPayServer.Abstractions.Models; +using BTCPayServer.Abstractions.Services; +using BTCPayServer.Lightning; +using Microsoft.Extensions.DependencyInjection; + +namespace BTCPayServer.Plugins.Blink +{ + + public class BlinkPlugin : BaseBTCPayServerPlugin + { + public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } = + { + new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"} + + }; + + public override void Execute(IServiceCollection applicationBuilder) + { + applicationBuilder.AddSingleton(new UIExtension("Blink/LNPaymentMethodSetupTab", "ln-payment-method-setup-tab")); + applicationBuilder.AddSingleton(provider => provider.GetRequiredService()); + applicationBuilder.AddSingleton(); + + base.Execute(applicationBuilder); + } + + } +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml b/Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml new file mode 100644 index 0000000..08b3c42 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml @@ -0,0 +1,39 @@ +@model BTCPayServer.Models.StoreViewModels.LightningNodeViewModel +@{ + var storeId = Model.StoreId; + if (Model.CryptoCode != "BTC") + { + return; + } +} + + + + \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Blink/Views/_ViewImports.cshtml b/Plugins/BTCPayServer.Plugins.Blink/Views/_ViewImports.cshtml new file mode 100644 index 0000000..cf06ff9 --- /dev/null +++ b/Plugins/BTCPayServer.Plugins.Blink/Views/_ViewImports.cshtml @@ -0,0 +1,9 @@ +@using BTCPayServer.Abstractions.Extensions +@inject BTCPayServer.Abstractions.Services.Safe Safe +@addTagHelper *, BTCPayServer.Abstractions +@addTagHelper *, BTCPayServer.TagHelpers +@addTagHelper *, BTCPayServer.Views.TagHelpers +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, BTCPayServer \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Breez/BTCPayServer.Plugins.Breez.csproj b/Plugins/BTCPayServer.Plugins.Breez/BTCPayServer.Plugins.Breez.csproj index fc639cf..6038060 100644 --- a/Plugins/BTCPayServer.Plugins.Breez/BTCPayServer.Plugins.Breez.csproj +++ b/Plugins/BTCPayServer.Plugins.Breez/BTCPayServer.Plugins.Breez.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 10 @@ -33,10 +33,7 @@ - - - - + diff --git a/Plugins/BTCPayServer.Plugins.Breez/BreezController.cs b/Plugins/BTCPayServer.Plugins.Breez/BreezController.cs index cfeb60e..354ae05 100644 --- a/Plugins/BTCPayServer.Plugins.Breez/BreezController.cs +++ b/Plugins/BTCPayServer.Plugins.Breez/BreezController.cs @@ -326,7 +326,7 @@ public class BreezController : Controller viewModel ??= new PaymentsViewModel(); - viewModel.Payments = client.Sdk.ListPayments(new ListPaymentsRequest(PaymentTypeFilter.ALL, null, null, true, + viewModel.Payments = client.Sdk.ListPayments(new ListPaymentsRequest(null, null, null, true, (uint?) viewModel.Skip, (uint?) viewModel.Count)); return View(viewModel); diff --git a/Plugins/BTCPayServer.Plugins.Breez/BreezLightningClient.cs b/Plugins/BTCPayServer.Plugins.Breez/BreezLightningClient.cs index 45195ca..5e6a3c9 100644 --- a/Plugins/BTCPayServer.Plugins.Breez/BreezLightningClient.cs +++ b/Plugins/BTCPayServer.Plugins.Breez/BreezLightningClient.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -135,7 +136,7 @@ public class BreezLightningClient : ILightningClient, IDisposable, EventListener public async Task ListInvoices(ListInvoicesParams request, CancellationToken cancellation = default) { - return Sdk.ListPayments(new ListPaymentsRequest(PaymentTypeFilter.RECEIVED, null, null, + return Sdk.ListPayments(new ListPaymentsRequest(new List(){PaymentTypeFilter.RECEIVED}, null, null, request?.PendingOnly is not true, (uint?) request?.OffsetIndex, null)) .Select(FromPayment).ToArray(); } @@ -153,7 +154,7 @@ public class BreezLightningClient : ILightningClient, IDisposable, EventListener public async Task ListPayments(ListPaymentsParams request, CancellationToken cancellation = default) { - return Sdk.ListPayments(new ListPaymentsRequest(PaymentTypeFilter.RECEIVED, null, null, null, + return Sdk.ListPayments(new ListPaymentsRequest(new List(){PaymentTypeFilter.RECEIVED}, null, null, null, (uint?) request?.OffsetIndex, null)) .Select(ToLightningPayment).ToArray(); } diff --git a/Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapIn.cshtml b/Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapIn.cshtml index 7a2bc92..793ed68 100644 --- a/Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapIn.cshtml +++ b/Plugins/BTCPayServer.Plugins.Breez/Views/Breez/SwapIn.cshtml @@ -8,9 +8,11 @@ @using BTCPayServer.Payments @using BTCPayServer.Plugins.Breez @using BTCPayServer.Security +@using BTCPayServer.Services @using NBitcoin @inject BreezService BreezService @inject BTCPayNetworkProvider BtcPayNetworkProvider +@inject TransactionLinkProviders TransactionLinkProviders @{ ViewData.SetActivePage("Breez", "Swap In", "SwapIn"); string storeId = Model switch @@ -36,6 +38,7 @@ var deriv = Context.GetStoreData().GetDerivationSchemeSettings(BtcPayNetworkProvider, "BTC"); var ni = sdk.NodeInfo(); var f = sdk.RecommendedFees(); + var pmi = new PaymentMethodId("BTC", PaymentTypes.BTCLike); } @@ -104,7 +107,7 @@ Unconfirmed transactions @foreach (var txId in inProgressSwap.unconfirmedTxIds) { - + } } @@ -115,7 +118,7 @@ Confirmed transactions @foreach (var txId in inProgressSwap.confirmedTxIds) { - + } } @@ -156,7 +159,7 @@ Unconfirmed transactions @foreach (var txId in refund.unconfirmedTxIds) { - + } } @@ -167,7 +170,7 @@ Confirmed transactions @foreach (var txId in refund.confirmedTxIds) { - + } } @@ -178,7 +181,7 @@ Refund transactions @foreach (var txId in refund.refundTxIds) { - + } } diff --git a/Plugins/BTCPayServer.Plugins.Breez/Views/Shared/Breez/BreezPaymentsTable.cshtml b/Plugins/BTCPayServer.Plugins.Breez/Views/Shared/Breez/BreezPaymentsTable.cshtml index 403047d..cb5a5b9 100644 --- a/Plugins/BTCPayServer.Plugins.Breez/Views/Shared/Breez/BreezPaymentsTable.cshtml +++ b/Plugins/BTCPayServer.Plugins.Breez/Views/Shared/Breez/BreezPaymentsTable.cshtml @@ -15,7 +15,7 @@ if (sdk is null) return; - data = sdk.ListPayments(new ListPaymentsRequest(PaymentTypeFilter.ALL, null, null, null, 0, 10)); + data = sdk.ListPayments(new ListPaymentsRequest(null, null, null, null, 0, 10)); } var isDashboard = Model is StoreDashboardViewModel; diff --git a/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayServer.Plugins.Wabisabi.csproj b/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayServer.Plugins.Wabisabi.csproj index 13a0ef4..2bc6b44 100644 --- a/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayServer.Plugins.Wabisabi.csproj +++ b/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayServer.Plugins.Wabisabi.csproj @@ -43,7 +43,7 @@ - +