diff --git a/BTCPayServerPlugins.sln b/BTCPayServerPlugins.sln index 8f064c2..49c4a6d 100644 --- a/BTCPayServerPlugins.sln +++ b/BTCPayServerPlugins.sln @@ -81,8 +81,8 @@ Global {B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU - {B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {B19C9F52-DC47-466D-8B5C-2D202B7B003F}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {AD9635BB-C70E-4676-BB04-900D51B01666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD9635BB-C70E-4676-BB04-900D51B01666}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD9635BB-C70E-4676-BB04-900D51B01666}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -97,48 +97,48 @@ Global {8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU - {8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {8F158B88-0FEE-44FF-8552-7C0F17D5C508}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Release|Any CPU.ActiveCfg = Release|Any CPU {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Release|Any CPU.Build.0 = Release|Any CPU {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU + {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {DF85EFA4-0EF5-4A99-853F-E6F9C88E3F8C}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Release|Any CPU.ActiveCfg = Release|Any CPU {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Release|Any CPU.Build.0 = Release|Any CPU {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU - {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {2C5C4DF9-BA1F-4671-9F24-B22D7C9C3D21}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Release|Any CPU.ActiveCfg = Release|Any CPU {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Release|Any CPU.Build.0 = Release|Any CPU {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU - {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {D7E7309D-C4F4-496A-B2C8-BC5D3991B9C0}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Release|Any CPU.Build.0 = Release|Any CPU {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU - {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {3F2E0BA0-9EA7-490F-894D-F9703F35B174}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {6295533A-F941-40CA-B889-FE6C0432ED53}.Release|Any CPU.ActiveCfg = Release|Any CPU {6295533A-F941-40CA-B889-FE6C0432ED53}.Release|Any CPU.Build.0 = Release|Any CPU {6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU {6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {6295533A-F941-40CA-B889-FE6C0432ED53}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU + {6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {6295533A-F941-40CA-B889-FE6C0432ED53}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {58863D86-3C78-4BEC-ACB6-2F82CC141210}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {58863D86-3C78-4BEC-ACB6-2F82CC141210}.Debug|Any CPU.Build.0 = Debug|Any CPU {58863D86-3C78-4BEC-ACB6-2F82CC141210}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -149,12 +149,12 @@ Global {58863D86-3C78-4BEC-ACB6-2F82CC141210}.Altcoins-Release|Any CPU.Build.0 = Release|Any CPU {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Release|Any CPU.Build.0 = Release|Any CPU - {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Release|Any CPU.ActiveCfg = Altcoins-Release|Any CPU {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Altcoins-Release|Any CPU.Build.0 = Altcoins-Release|Any CPU + {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.ActiveCfg = Altcoins-Debug|Any CPU + {B4E2ED08-4AD3-4648-8BDB-3107200460B9}.Debug|Any CPU.Build.0 = Altcoins-Debug|Any CPU {5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Debug|Any CPU.Build.0 = Debug|Any CPU {5E1BAA06-7828-47BC-89D6-19C2A78EA427}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/BTCPayServerPlugins.sln.DotSettings.user b/BTCPayServerPlugins.sln.DotSettings.user index 0a4ed66..9d0765d 100644 --- a/BTCPayServerPlugins.sln.DotSettings.user +++ b/BTCPayServerPlugins.sln.DotSettings.user @@ -1,4 +1,4 @@  - True + True \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs index ca57b7d..b0ee4fa 100644 --- a/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs +++ b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningClient.cs @@ -1,23 +1,17 @@ #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 Microsoft.AspNetCore.OutputCaching; using NBitcoin; -using NBitpayClient; using Newtonsoft.Json.Linq; using Network = NBitcoin.Network; @@ -32,18 +26,20 @@ public class BlinkLightningClient : ILightningClient public string? WalletCurrency { get; set; } 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) + public BlinkLightningClient(string apiKey, Uri apiEndpoint, string walletId, Network network, HttpClient httpClient) { _apiKey = apiKey; _apiEndpoint = apiEndpoint; WalletId = walletId; _network = network; - _nbXplorerDashboard = nbXplorerDashboard; - _client = new GraphQLHttpClient(new GraphQLHttpClientOptions() {EndPoint = _apiEndpoint}, new NewtonsoftJsonSerializer(), httpClient); + _client = new GraphQLHttpClient(new GraphQLHttpClientOptions() {EndPoint = _apiEndpoint, WebSocketEndPoint = new Uri( "wss://" + _apiEndpoint.Host.Replace("api.", "ws.") + _apiEndpoint.PathAndQuery), ConfigureWebsocketOptions = + options => + { + options.SetRequestHeader("X-API-KEY", apiKey); + }}, new NewtonsoftJsonSerializer(), httpClient); + } @@ -301,23 +297,9 @@ query Transactions($walletId: WalletId!) { public async Task CreateInvoice(CreateInvoiceParams createInvoiceRequest, CancellationToken cancellation = new()) { - var query = @" -mutation lnInvoiceCreate($input: LnInvoiceCreateOnBehalfOfRecipientInput!) { - lnInvoiceCreateOnBehalfOfRecipient(input: $input) { - invoice { - createdAt - paymentHash - paymentRequest - paymentSecret - paymentStatus - satoshis - } - } -}"; + string query; - if (WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true) - { - query = @" + query = WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true ? @" mutation lnInvoiceCreate($input: LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput!) { lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient(input: $input) { invoice { @@ -327,10 +309,27 @@ mutation lnInvoiceCreate($input: LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecip paymentSecret paymentStatus satoshis + }, + errors{ + message + } + } +}" : @" +mutation lnInvoiceCreate($input: LnInvoiceCreateOnBehalfOfRecipientInput!) { + lnInvoiceCreateOnBehalfOfRecipient(input: $input) { + invoice { + createdAt + paymentHash + paymentRequest + paymentSecret + paymentStatus + satoshis + }, + errors{ + message } } }"; - } var reques = new GraphQLRequest { @@ -350,142 +349,101 @@ expiresIn = (int)createInvoiceRequest.Expiry.TotalMinutes } }; var response = await _client.SendQueryAsync(reques, cancellation); - - - return ToInvoice(response.Data.lnInvoiceCreate.invoice); + var inv = (WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true + ? response.Data.lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient.invoice + : response.Data.lnInvoiceCreateOnBehalfOfRecipient.invoice)as JObject; + + if (inv is null) + { + var errors = (WalletCurrency?.Equals("btc", StringComparison.InvariantCultureIgnoreCase) is not true + ? response.Data.lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient.errors + : response.Data.lnInvoiceCreateOnBehalfOfRecipient.errors) as JArray; + + if (errors.Any()) + { + throw new Exception(errors.First()["message"].ToString()); + } + } + return ToInvoice(inv); } public async Task Listen(CancellationToken cancellation = new CancellationToken()) { - return new BlinkListener(this, cancellation); + return new BlinkListener(_client, this); } - public class BlinkListener : ILightningInvoiceListener { - private readonly ILightningClient _client; + private readonly BlinkLightningClient _lightningClient; 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; + private readonly IDisposable _subscription; - public BlinkListener(ILightningClient client, CancellationToken cancellation) + public BlinkListener(GraphQLHttpClient httpClient, BlinkLightningClient lightningClient) { - _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellation); - _client = client; - _paidInvoiceIds = new List(); - _listenLoop = ListenLoop(); + try + { + + _lightningClient = lightningClient; + var stream = httpClient.CreateSubscriptionStream(new GraphQLRequest() + { + Query = @"subscription myUpdates { + myUpdates { + update { + ... on LnUpdate { + transaction { + initiationVia { + ... on InitiationViaLn { + paymentHash + } + } + direction + } + } + } + } +} +", OperationName = "myUpdates" + }); + + _subscription = stream.Subscribe(async response => + { + try + { + var x = stream; + var y = _lightningClient; + if (response.Data.myUpdates.update.transaction.direction != "RECEIVE") + return; + if ((await _lightningClient.GetInvoice(response.Data.myUpdates.update.transaction.initiationVia + .paymentHash.ToString())) is LightningInvoice inv) + { + + _invoices.Writer.TryWrite(inv); + } + } + catch (Exception e) + { + Console.WriteLine(e); + } + + }); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + public void Dispose() + { + _subscription.Dispose(); + _invoices.Writer.TryComplete(); } 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(); + return await _invoices.Reader.ReadAsync(cancellation); } } - - public async Task<(Network Network, string DefaultWalletId)> GetNetworkAndDefaultWallet(CancellationToken cancellation =default) + public async Task<(Network Network, string DefaultWalletId, string DefaultWalletCurrency)> GetNetworkAndDefaultWallet(CancellationToken cancellation =default) { var reques = new GraphQLRequest @@ -497,7 +455,10 @@ query GetNetworkAndDefaultWallet { } me { defaultAccount { - defaultWalletId + defaultWallet{ + id + currency + } } } }", @@ -506,7 +467,8 @@ query GetNetworkAndDefaultWallet { var response = await _client.SendQueryAsync(reques, cancellation); - var defaultWalletId = (string) response.Data.me.defaultAccount.defaultWalletId; + var defaultWalletId = (string) response.Data.me.defaultAccount.defaultWallet.id; + var defaultWalletCurrency = (string) response.Data.me.defaultAccount.defaultWallet.currency; var network = response.Data.globals.network.ToString() switch { "mainnet" => Network.Main, @@ -514,31 +476,13 @@ query GetNetworkAndDefaultWallet { "regtest" => Network.RegTest, _ => throw new ArgumentOutOfRangeException() }; - return (network, defaultWalletId); + return (network, defaultWalletId, defaultWalletCurrency); } - public async Task GetInfo(CancellationToken cancellation = new CancellationToken()) + public 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; + + throw new NotSupportedException(); } public async Task GetBalance(CancellationToken cancellation = new()) diff --git a/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs index 83dd3f6..be5074a 100644 --- a/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs +++ b/Plugins/BTCPayServer.Plugins.Blink/BlinkLightningConnectionStringHandler.cs @@ -2,7 +2,6 @@ using System; using System.Linq; using System.Net.Http; -using BTCPayServer.HostedServices; using BTCPayServer.Lightning; using Network = NBitcoin.Network; @@ -11,13 +10,10 @@ namespace BTCPayServer.Plugins.Blink; public class BlinkLightningConnectionStringHandler : ILightningConnectionStringHandler { private readonly IHttpClientFactory _httpClientFactory; - private readonly NBXplorerDashboard _nbXplorerDashboard; - public BlinkLightningConnectionStringHandler(IHttpClientFactory httpClientFactory, - NBXplorerDashboard nbXplorerDashboard) + public BlinkLightningConnectionStringHandler(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; - _nbXplorerDashboard = nbXplorerDashboard; } @@ -32,8 +28,9 @@ public class BlinkLightningConnectionStringHandler : ILightningConnectionStringH if (!kv.TryGetValue("server", out var server)) { - error = $"The key 'server' is mandatory for blink connection strings"; - return null; + server = "https://api.blink.sv/graphql"; + // error = $"The key 'server' is mandatory for blink connection strings"; + // return null; } if (!Uri.TryCreate(server, UriKind.Absolute, out var uri) @@ -77,8 +74,8 @@ public class BlinkLightningConnectionStringHandler : ILightningConnectionStringH client.BaseAddress = uri; kv.TryGetValue("wallet-id", out var walletId); - var bclient = new BlinkLightningClient(apiKey, uri, walletId, network, _nbXplorerDashboard, client); - (Network Network, string DefaultWalletId) res; + var bclient = new BlinkLightningClient(apiKey, uri, walletId, network, client); + (Network Network, string DefaultWalletId, string DefaultWalletCurrency) res; try { res = bclient.GetNetworkAndDefaultWallet().GetAwaiter().GetResult(); @@ -103,6 +100,7 @@ public class BlinkLightningConnectionStringHandler : ILightningConnectionStringH if (walletId is null) { bclient.WalletId = res.DefaultWalletId; + bclient.WalletCurrency = res.DefaultWalletCurrency; } else { diff --git a/Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml b/Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml index 6d57cbf..fa54a3c 100644 --- a/Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml +++ b/Plugins/BTCPayServer.Plugins.Blink/Views/Shared/Blink/LNPaymentMethodSetupTab.cshtml @@ -32,7 +32,7 @@ type=blink;server=https://api.blink.sv/graphql;api-key=blink_...;wallet-id=xyz -

Head over to the Blink dashboard and create an api key. The wallet-id is optional and will use the default wallet otherwise.

+

Head over to the Blink dashboard and create an api key. The server is optional and will use the default Blink instance.The wallet-id is optional and will use the default wallet otherwise.

diff --git a/Plugins/BTCPayServer.Plugins.LiquidPlus/BTCPayServer.Plugins.LiquidPlus.csproj b/Plugins/BTCPayServer.Plugins.LiquidPlus/BTCPayServer.Plugins.LiquidPlus.csproj index 7459f2c..26db225 100644 --- a/Plugins/BTCPayServer.Plugins.LiquidPlus/BTCPayServer.Plugins.LiquidPlus.csproj +++ b/Plugins/BTCPayServer.Plugins.LiquidPlus/BTCPayServer.Plugins.LiquidPlus.csproj @@ -5,6 +5,7 @@ 10 Debug;Release;Altcoins-Debug;Altcoins-Release AnyCPU + $(DefineConstants);ALTCOINS @@ -31,18 +32,6 @@ - - - true - - - - true - - - - $(DefineConstants);ALTCOINS - diff --git a/Plugins/BTCPayServer.Plugins.LiquidPlus/Controllers/StoreLiquidController.cs b/Plugins/BTCPayServer.Plugins.LiquidPlus/Controllers/StoreLiquidController.cs index 21b04c5..78196c7 100644 --- a/Plugins/BTCPayServer.Plugins.LiquidPlus/Controllers/StoreLiquidController.cs +++ b/Plugins/BTCPayServer.Plugins.LiquidPlus/Controllers/StoreLiquidController.cs @@ -10,6 +10,7 @@ using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; using BTCPayServer.Client; using BTCPayServer.Common; +using BTCPayServer.Plugins.Altcoins; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewFeatures; diff --git a/Plugins/BTCPayServer.Plugins.LiquidPlus/LiquidPlusPlugin.cs b/Plugins/BTCPayServer.Plugins.LiquidPlus/LiquidPlusPlugin.cs index 4ca37eb..11f5d1f 100644 --- a/Plugins/BTCPayServer.Plugins.LiquidPlus/LiquidPlusPlugin.cs +++ b/Plugins/BTCPayServer.Plugins.LiquidPlus/LiquidPlusPlugin.cs @@ -1,14 +1,20 @@ using System; -using System.Collections.Generic; using System.Linq; using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Abstractions.Models; using BTCPayServer.Abstractions.Services; +using BTCPayServer.Configuration; +using BTCPayServer.Hosting; +using BTCPayServer.Payments; +using BTCPayServer.Plugins.Altcoins; using BTCPayServer.Plugins.LiquidPlus.Services; +using BTCPayServer.Services; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using NBitcoin; +using NBXplorer; namespace BTCPayServer.Plugins.LiquidPlus { @@ -16,78 +22,75 @@ namespace BTCPayServer.Plugins.LiquidPlus { public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } = { - new() { Identifier = nameof(BTCPayServer), Condition = ">=1.12.0" } + new() {Identifier = nameof(BTCPayServer), Condition = ">=1.12.0"} }; - public override void Execute(IServiceCollection services) + + public override void Execute(IServiceCollection applicationBuilder) { + var services = (PluginServiceCollection) applicationBuilder; + if (services.BootstrapServices.GetRequiredService() + .GetFromCryptoCode("LBTC") is null || !services.BootstrapServices.GetRequiredService().Contains("LBTC")) + return; services.AddSingleton(new UIExtension("LiquidNav", "store-integrations-nav")); - services.AddSingleton(new UIExtension("OnChainWalletSetupLiquidExtension", "onchain-wallet-setup-post-body")); + services.AddSingleton(new UIExtension("OnChainWalletSetupLiquidExtension", + "onchain-wallet-setup-post-body")); services.AddSingleton(new UIExtension("CustomLiquidAssetsNavExtension", "server-nav")); - services.AddSingleton(new UIExtension("StoreNavLiquidExtension", "store-nav")); + services.AddSingleton(new UIExtension("StoreNavLiquidExtension", "store-nav")); services.AddSingleton(); - var originalImplementationFactory = services.Single(descriptor => - descriptor.Lifetime == ServiceLifetime.Singleton && - descriptor.ServiceType == typeof(BTCPayNetworkProvider)); - services.Replace(ServiceDescriptor.Singleton(provider => - { - var _customLiquidAssetsRepository = provider.GetService(); - var _logger = provider.GetService>(); - var networkProvider = - (originalImplementationFactory.ImplementationInstance ?? - originalImplementationFactory.ImplementationFactory.Invoke(provider)) as BTCPayNetworkProvider; - if (networkProvider.Support("LBTC")) - { - var settings = _customLiquidAssetsRepository.Get(); - var template = networkProvider.GetNetwork("LBTC"); - var additionalNetworks = settings.Items.Select(configuration => new ElementsBTCPayNetwork() + + var config = services.BootstrapServices.GetRequiredService(); + DataDirectories dataDirectories = new DataDirectories(); + dataDirectories.Configure(config); + + var repo = new CustomLiquidAssetsRepository(new NullLogger(), + new OptionsWrapper(dataDirectories)); + var settings = repo.Get(); + var template = (ElementsBTCPayNetwork) services.Single(descriptor => + descriptor.ServiceType == typeof(BTCPayNetworkBase) && + descriptor.ImplementationInstance is ElementsBTCPayNetwork { - CryptoCode = configuration.CryptoCode - .Replace("-", "") - .Replace("_", ""), - DefaultRateRules = configuration.DefaultRateRules ?? Array.Empty(), - AssetId = uint256.Parse(configuration.AssetId), - Divisibility = configuration.Divisibility, - DisplayName = configuration.DisplayName, - CryptoImagePath = configuration.CryptoImagePath, - NetworkCryptoCode = template.NetworkCryptoCode, - DefaultSettings = template.DefaultSettings, - ElectrumMapping = template.ElectrumMapping, - BlockExplorerLink = template.BlockExplorerLink, - ReadonlyWallet = template.ReadonlyWallet, - SupportLightning = false, - SupportPayJoin = false, - ShowSyncSummary = false, - WalletSupported = template.WalletSupported, - LightningImagePath = "", - NBXplorerNetwork = template.NBXplorerNetwork, - CoinType = template.CoinType, - VaultSupported = template.VaultSupported, - MaxTrackedConfirmation = template.MaxTrackedConfirmation, - BlockExplorerLinkDefault = template.BlockExplorerLinkDefault, - SupportRBF = template.SupportRBF - }); - var newCryptoCodes = settings.Items.Select(configuration => configuration.CryptoCode).ToArray(); - _logger.LogInformation($"Loaded {newCryptoCodes.Length} " + - $"{(!newCryptoCodes.Any()?string.Empty: $"({string.Join(',', newCryptoCodes)})")} additional liquid assets"); - var newSupportedChains = networkProvider.GetAll().Select(b => b.CryptoCode).Concat(newCryptoCodes).ToArray(); - return new BTCPayNetworkProviderOverride(networkProvider.NetworkType, additionalNetworks).Filter(newSupportedChains); - } + CryptoCode: "LBTC" + }) + .ImplementationInstance; + var tlProvider = (TransactionLinkProviders.Entry) services.Single(descriptor => + descriptor.ServiceType == typeof(TransactionLinkProviders.Entry) && + descriptor.ImplementationInstance is TransactionLinkProviders.Entry + { + PaymentMethodId: {CryptoCode: "LBTC"} + }) + .ImplementationInstance; + settings.Items.ForEach(configuration => - return networkProvider; - })); - } - } - - public class BTCPayNetworkProviderOverride : BTCPayNetworkProvider - { - public BTCPayNetworkProviderOverride(ChainName networkType, - IEnumerable elementsBTCPayNetworks) : base(networkType) - { - foreach (ElementsBTCPayNetwork elementsBTCPayNetwork in elementsBTCPayNetworks) { - _Networks.TryAdd(elementsBTCPayNetwork.CryptoCode.ToUpperInvariant(), elementsBTCPayNetwork); - } + var code = configuration.CryptoCode + .Replace("-", "") + .Replace("_", ""); + services.AddBTCPayNetwork(new ElementsBTCPayNetwork() + { + CryptoCode = code, + DefaultRateRules = configuration.DefaultRateRules ?? Array.Empty(), + AssetId = uint256.Parse(configuration.AssetId), + Divisibility = configuration.Divisibility, + DisplayName = configuration.DisplayName, + CryptoImagePath = configuration.CryptoImagePath, + NetworkCryptoCode = template.NetworkCryptoCode, + DefaultSettings = template.DefaultSettings, + ElectrumMapping = template.ElectrumMapping, + BlockExplorerLink = template.BlockExplorerLink, + ReadonlyWallet = template.ReadonlyWallet, + SupportLightning = false, + SupportPayJoin = false, + ShowSyncSummary = false, + WalletSupported = template.WalletSupported, + LightningImagePath = "", + NBXplorerNetwork = template.NBXplorerNetwork, + CoinType = template.CoinType, + VaultSupported = template.VaultSupported, + MaxTrackedConfirmation = template.MaxTrackedConfirmation, + SupportRBF = template.SupportRBF + }).AddTransactionLinkProvider(new PaymentMethodId(code, PaymentTypes.BTCLike), tlProvider.Provider); + }); } } -} +} \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.LiquidPlus/Views/Shared/LiquidNav.cshtml b/Plugins/BTCPayServer.Plugins.LiquidPlus/Views/Shared/LiquidNav.cshtml index 17c9e01..2aa6acc 100644 --- a/Plugins/BTCPayServer.Plugins.LiquidPlus/Views/Shared/LiquidNav.cshtml +++ b/Plugins/BTCPayServer.Plugins.LiquidPlus/Views/Shared/LiquidNav.cshtml @@ -1,6 +1,9 @@ @using BTCPayServer @using BTCPayServer.Abstractions.Contracts +@using BTCPayServer.Client +@using BTCPayServer.Plugins.Altcoins @using BTCPayServer.Plugins.LiquidPlus.Controllers +@using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.AspNetCore.Routing @inject BTCPayNetworkProvider BTCPayNetworkProvider; @@ -13,7 +16,7 @@ } @if (!string.IsNullOrEmpty(storeId) && (BTCPayNetworkProvider.GetAll().OfType().Any())) { -