diff --git a/Plugins/BTCPayServer.Plugins.NIP05/BTCPayServer.Plugins.NIP05.csproj b/Plugins/BTCPayServer.Plugins.NIP05/BTCPayServer.Plugins.NIP05.csproj
index e9f35c5..ec82866 100644
--- a/Plugins/BTCPayServer.Plugins.NIP05/BTCPayServer.Plugins.NIP05.csproj
+++ b/Plugins/BTCPayServer.Plugins.NIP05/BTCPayServer.Plugins.NIP05.csproj
@@ -11,7 +11,7 @@
Nostr
NIP5 addresses, Zap support, Nostr Wallet Connect Lightning support
- 1.1.9
+ 1.1.10
true
diff --git a/Plugins/BTCPayServer.Plugins.NIP05/Nip05Plugin.cs b/Plugins/BTCPayServer.Plugins.NIP05/Nip05Plugin.cs
index 8b317d7..fdb5492 100644
--- a/Plugins/BTCPayServer.Plugins.NIP05/Nip05Plugin.cs
+++ b/Plugins/BTCPayServer.Plugins.NIP05/Nip05Plugin.cs
@@ -4,6 +4,8 @@ using BTCPayServer.Abstractions.Models;
using BTCPayServer.Abstractions.Services;
using BTCPayServer.Lightning;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using NNostr.Client;
namespace BTCPayServer.Plugins.NIP05
{
@@ -22,6 +24,7 @@ namespace BTCPayServer.Plugins.NIP05
applicationBuilder.AddSingleton();
applicationBuilder.AddSingleton();
+ applicationBuilder.TryAddSingleton();
applicationBuilder.AddSingleton();
applicationBuilder.AddHostedService(sp => sp.GetRequiredService());
applicationBuilder.AddSingleton();
diff --git a/Plugins/BTCPayServer.Plugins.NIP05/NostrClientPool.cs b/Plugins/BTCPayServer.Plugins.NIP05/NostrClientPool.cs
deleted file mode 100644
index 1e66750..0000000
--- a/Plugins/BTCPayServer.Plugins.NIP05/NostrClientPool.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Threading;
-using System.Threading.Tasks;
-using NNostr.Client;
-using NNostr.Client.Protocols;
-
-namespace BTCPayServer.Plugins.NIP05;
-
-public class NostrClientPool
-{
- private static readonly ConcurrentDictionary _clientPool = new();
-
- private static readonly Timer _cleanupTimer;
-
- static NostrClientPool()
- {
- _cleanupTimer = new Timer(CleanupExpiredClients, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
- }
-
- public static (INostrClient, IDisposable) GetClient(string connstring)
- {
- var connParams = NIP47.ParseUri(new Uri(connstring));
-
- var clientWrapper = _clientPool.GetOrAdd(connstring.ToString(),
- k => new NostrClientWrapper(new CompositeNostrClient(connParams.relays)));
-
- clientWrapper.IncrementUsage();
-
- return (clientWrapper.Client, new UsageDisposable(clientWrapper));
- }
- public static async Task<(INostrClient, IDisposable)> GetClientAndConnect(string connstring, CancellationToken token)
- {
- var result = GetClient(connstring);
-
- await result.Item1.ConnectAndWaitUntilConnected(token, CancellationToken.None);
-
- return result;
- }
-
- public static void KillClient(string connstring)
- {
- if (_clientPool.TryRemove(connstring, out var clientWrapper))
- {
- clientWrapper.Dispose();
- }
- }
-
- private static void CleanupExpiredClients(object state)
- {
- foreach (var key in _clientPool.Keys)
- {
- if (_clientPool[key].IsExpired())
- {
- if (_clientPool.TryRemove(key, out var clientWrapper))
- {
- clientWrapper.Dispose();
- }
- }
- }
- }
-
- private class UsageDisposable : IDisposable
- {
- private readonly NostrClientWrapper _clientWrapper;
-
- public UsageDisposable(NostrClientWrapper clientWrapper)
- {
- _clientWrapper = clientWrapper;
- }
-
- public void Dispose()
- {
- _clientWrapper.DecrementUsage();
- }
- }
-}
\ No newline at end of file
diff --git a/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningClient.cs b/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningClient.cs
index c71e4e3..364b63e 100644
--- a/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningClient.cs
+++ b/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningClient.cs
@@ -16,14 +16,16 @@ namespace BTCPayServer.Plugins.NIP05;
public class NostrWalletConnectLightningClient : ILightningClient
{
+ private readonly NostrClientPool _nostrClientPool;
private readonly Uri _uri;
private readonly Network _network;
private readonly (string[] Commands, string[] Notifications) _commands;
private readonly (ECXOnlyPubKey pubkey, ECPrivKey secret, Uri[] relays, string lud16) _connectParams;
- public NostrWalletConnectLightningClient(Uri uri, Network network,
+ public NostrWalletConnectLightningClient(NostrClientPool nostrClientPool, Uri uri, Network network,
(string[] Commands, string[] Notifications) commands)
{
+ _nostrClientPool = nostrClientPool;
_uri = uri;
_network = network;
_commands = commands;
@@ -77,7 +79,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
public async Task GetInvoice(uint256 paymentHash,
CancellationToken cancellation = new CancellationToken())
{
- var (nostrClient, usage) = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var (nostrClient, usage) = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
using (usage)
{
@@ -99,7 +101,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
public async Task ListInvoices(ListInvoicesParams request,
CancellationToken cancellation = new CancellationToken())
{
- var (client, usage) = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var (client, usage) = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
using (usage)
{
@@ -154,7 +156,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
public async Task GetPayment(string paymentHash,
CancellationToken cancellation = new CancellationToken())
{
- var (client, usage) = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var (client, usage) = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
using (usage)
{
@@ -175,7 +177,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
public async Task ListPayments(ListPaymentsParams request,
CancellationToken cancellation = new CancellationToken())
{
- var (client, usage) = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var (client, usage) = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
using (usage)
{
@@ -200,7 +202,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
public async Task CreateInvoice(CreateInvoiceParams createInvoiceRequest,
CancellationToken cancellation = new CancellationToken())
{
- var (client, usage) = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var (client, usage) = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
using (usage)
{
@@ -221,7 +223,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
public async Task Listen(CancellationToken cancellation = new CancellationToken())
{
- var x = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var x = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
if (_commands.Notifications?.Contains("payment_received") is true)
{
return new NotificationListener(_network, x, _connectParams);
@@ -361,7 +363,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
public async Task GetBalance(CancellationToken cancellation = new CancellationToken())
{
- var (client, usage) = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var (client, usage) = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
using (usage)
{
@@ -389,7 +391,7 @@ public class NostrWalletConnectLightningClient : ILightningClient
{
try
{
- var (client, usage) = await NostrClientPool.GetClientAndConnect(_uri.ToString(), cancellation);
+ var (client, usage) = await _nostrClientPool.GetClientAndConnect(_connectParams.relays, cancellation);
using (usage)
{
diff --git a/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningConnectionStringHandler.cs b/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningConnectionStringHandler.cs
index 6f8735c..b0caf6c 100644
--- a/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningConnectionStringHandler.cs
+++ b/Plugins/BTCPayServer.Plugins.NIP05/NostrWalletConnectLightningConnectionStringHandler.cs
@@ -4,13 +4,19 @@ using System.Linq;
using System.Threading;
using BTCPayServer.Lightning;
using NBitcoin;
+using NNostr.Client;
using NNostr.Client.Protocols;
namespace BTCPayServer.Plugins.NIP05;
public class NostrWalletConnectLightningConnectionStringHandler : ILightningConnectionStringHandler
{
-
+ private readonly NostrClientPool _nostrClientPool;
+
+ public NostrWalletConnectLightningConnectionStringHandler(NostrClientPool nostrClientPool)
+ {
+ _nostrClientPool = nostrClientPool;
+ }
public ILightningClient? Create(string connectionString, Network network, out string? error)
{
@@ -27,7 +33,7 @@ public class NostrWalletConnectLightningConnectionStringHandler : ILightningConn
Uri.TryCreate(connectionString, UriKind.Absolute, out var uri);
var connectParams = NIP47.ParseUri(uri); var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(10));
- var (client, disposable) = NostrClientPool.GetClientAndConnect(connectionString, cts.Token).ConfigureAwait(false).GetAwaiter().GetResult();
+ var (client, disposable) = _nostrClientPool.GetClientAndConnect(connectParams.relays, cts.Token).ConfigureAwait(false).GetAwaiter().GetResult();
using (disposable)
{
var commands = client.FetchNIP47AvailableCommands(connectParams.Item1, cancellationToken: cts.Token)
@@ -55,7 +61,7 @@ public class NostrWalletConnectLightningConnectionStringHandler : ILightningConn
}
error = null;
- return new NostrWalletConnectLightningClient(uri, network, commands.Value);
+ return new NostrWalletConnectLightningClient(_nostrClientPool, uri, network, commands.Value);
}
}
catch (Exception e)
diff --git a/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs b/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs
index 2233864..4c6a759 100644
--- a/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs
+++ b/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs
@@ -15,33 +15,11 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using NBitcoin;
-using NBitcoin.Secp256k1;
-using Newtonsoft.Json;
using NNostr.Client;
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace BTCPayServer.Plugins.NIP05;
-public class ZapperSettings
-{
- public ZapperSettings(string ZapperPrivateKey)
- {
- this.ZapperPrivateKey = ZapperPrivateKey;
- }
-
- public ZapperSettings()
- {
-
- }
-
- [JsonIgnore]
- public ECPrivKey ZappingKey => NostrExtensions.ParseKey(ZapperPrivateKey);
- [JsonIgnore]
- public ECXOnlyPubKey ZappingPublicKey => ZappingKey.CreateXOnlyPubKey();
- [JsonIgnore]
- public string ZappingPublicKeyHex => ZappingPublicKey.ToHex();
- public string ZapperPrivateKey { get; set; }
-}
public class Zapper : IHostedService
{
record PendingZapEvent(string[] relays, NostrEvent nostrEvent);
@@ -54,7 +32,7 @@ public class Zapper : IHostedService
private readonly InvoiceRepository _invoiceRepository;
private IEventAggregatorSubscription _subscription;
private readonly ConcurrentBag _pendingZapEvents = new();
- private readonly NNostr.Client.NostrClientPool _nostrClientPool;
+ private readonly NostrClientPool _nostrClientPool;
public async Task GetSettings()
{
@@ -78,7 +56,8 @@ public class Zapper : IHostedService
IMemoryCache memoryCache,
ILogger logger,
SettingsRepository settingsRepository,
- InvoiceRepository invoiceRepository)
+ InvoiceRepository invoiceRepository,
+ NostrClientPool nostrClientPool)
{
_eventAggregator = eventAggregator;
_nip5Controller = nip5Controller;
@@ -86,7 +65,7 @@ public class Zapper : IHostedService
_logger = logger;
_settingsRepository = settingsRepository;
_invoiceRepository = invoiceRepository;
- _nostrClientPool = new NNostr.Client.NostrClientPool();
+ _nostrClientPool = nostrClientPool;
}
public Task StartAsync(CancellationToken cancellationToken)
diff --git a/Plugins/BTCPayServer.Plugins.NIP05/ZapperSettings.cs b/Plugins/BTCPayServer.Plugins.NIP05/ZapperSettings.cs
new file mode 100644
index 0000000..99f2fae
--- /dev/null
+++ b/Plugins/BTCPayServer.Plugins.NIP05/ZapperSettings.cs
@@ -0,0 +1,26 @@
+using NBitcoin.Secp256k1;
+using Newtonsoft.Json;
+using NNostr.Client;
+
+namespace BTCPayServer.Plugins.NIP05;
+
+public class ZapperSettings
+{
+ public ZapperSettings(string ZapperPrivateKey)
+ {
+ this.ZapperPrivateKey = ZapperPrivateKey;
+ }
+
+ public ZapperSettings()
+ {
+
+ }
+
+ [JsonIgnore]
+ public ECPrivKey ZappingKey => NostrExtensions.ParseKey(ZapperPrivateKey);
+ [JsonIgnore]
+ public ECXOnlyPubKey ZappingPublicKey => ZappingKey.CreateXOnlyPubKey();
+ [JsonIgnore]
+ public string ZappingPublicKeyHex => ZappingPublicKey.ToHex();
+ public string ZapperPrivateKey { get; set; }
+}
\ No newline at end of file
diff --git a/Plugins/BTCPayServer.Plugins.NIP05/readme.md b/Plugins/BTCPayServer.Plugins.NIP05/readme.md
index 703cd2e..2d69496 100644
--- a/Plugins/BTCPayServer.Plugins.NIP05/readme.md
+++ b/Plugins/BTCPayServer.Plugins.NIP05/readme.md
@@ -1,6 +1,10 @@
# BTCPay Server NIP05 Support
-This plugin allows your BTCPay Server to support the [Nostr](https://github.com/nostr-protocol/nostr)[ NIP05 protocol](https://github.com/nostr-protocol/nips/blob/master/05.md) to verify accounts.
+This plugin allows your BTCPay Server to support
+
+* [Nostr](https://github.com/nostr-protocol/nostr)[ NIP05 protocol](https://github.com/nostr-protocol/nips/blob/master/05.md) to verify accounts.
+* [Nostr](https://github.com/nostr-protocol/nostr)[ NIP57 protocol](https://github.com/nostr-protocol/nips/blob/master/57.md) to support Zaps.
+* [Nostr](https://github.com/nostr-protocol/nostr)[ NIP47 protocol](https://github.com/nostr-protocol/nips/blob/master/47.md) to accept payments to your NWC enabled lightning wallet.
## Usage