From c9a5dbc7d142b4a44217db62328859add71fb665 Mon Sep 17 00:00:00 2001 From: Kukks Date: Sun, 23 Apr 2023 11:31:56 +0200 Subject: [PATCH] improve --- BTCPayServerPlugins.sln.DotSettings.user | 3 +- .../Nip5Controller.cs | 34 ++++++--- Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs | 73 +++++++++++++------ .../BTCPayServer.Plugins.Prism/SatBreaker.cs | 2 +- .../BTCPayCoinjoinCoinSelector.cs | 11 ++- .../UpdateWabisabiStoreSettings.cshtml | 2 +- submodules/walletwasabi | 2 +- 7 files changed, 89 insertions(+), 38 deletions(-) diff --git a/BTCPayServerPlugins.sln.DotSettings.user b/BTCPayServerPlugins.sln.DotSettings.user index ee25a68..1ff6a17 100644 --- a/BTCPayServerPlugins.sln.DotSettings.user +++ b/BTCPayServerPlugins.sln.DotSettings.user @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/Plugins/BTCPayServer.Plugins.NIP05/Nip5Controller.cs b/Plugins/BTCPayServer.Plugins.NIP05/Nip5Controller.cs index 4b7527a..180cdd0 100644 --- a/Plugins/BTCPayServer.Plugins.NIP05/Nip5Controller.cs +++ b/Plugins/BTCPayServer.Plugins.NIP05/Nip5Controller.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using NBitcoin.DataEncoders; -using NBitcoin.Secp256k1; using NNostr.Client; using NNostr.Client.Protocols; @@ -38,21 +37,35 @@ public class Nip5Controller : Controller [HttpGet] public async Task Edit(string storeId) { - var settings = await _storeRepository.GetSettingAsync(storeId, "NIP05"); + var settings = await GetForStore(storeId); return View(settings ?? new()); } +[NonAction] + public async Task GetForStore(string storeId) + { + return await _memoryCache.GetOrCreateAsync("NIP05_" + storeId, async entry => await _storeRepository.GetSettingAsync(storeId, "NIP05")); + + } + + [NonAction] + public async Task UpdateStore(string storeId, Nip5StoreSettings? settings) + { + _memoryCache.Remove("NIP05_" + storeId); + await _storeRepository.UpdateSetting(storeId, "NIP05", settings); + _memoryCache.CreateEntry("NIP05_" + storeId).SetValue(settings); + } [HttpPost] public async Task Edit(string storeId, Nip5StoreSettings settings, string command) { + + var existingSettings = await GetForStore(storeId); if (command == "remove") { - var settingss = await _storeRepository.GetSettingAsync(storeId, "NIP05"); - if (settingss is not null) + if (existingSettings is not null) { - await _storeRepository.UpdateSetting(storeId, "NIP05", null); - - _memoryCache.Remove($"NIP05_{settingss.Name.ToLowerInvariant()}"); + await UpdateStore(storeId, null); + _memoryCache.Remove($"NIP05_{existingSettings.Name.ToLowerInvariant()}"); } return RedirectToAction("Edit", new {storeId}); @@ -139,13 +152,12 @@ k = settings.PrivateKey.FromNIP19Nsec(); return View(settings); } - var settingssx = await _storeRepository.GetSettingAsync(storeId, "NIP05"); - if (settingssx is not null) + if (existingSettings?.Name is not null) { - _memoryCache.Remove($"NIP05_{settingssx.Name.ToLowerInvariant()}"); + _memoryCache.Remove($"NIP05_{existingSettings.Name.ToLowerInvariant()}"); } - await _storeRepository.UpdateSetting(storeId, "NIP05", settings); + await UpdateStore(storeId, settings); return RedirectToAction("Edit", new {storeId}); } [NonAction] diff --git a/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs b/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs index e6c8501..9bc2c6d 100644 --- a/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs +++ b/Plugins/BTCPayServer.Plugins.NIP05/Zapper.cs @@ -7,14 +7,25 @@ using System.Threading; using System.Threading.Tasks; using BTCPayServer.Events; using BTCPayServer.Payments; +using BTCPayServer.Services; +using BTCPayServer.Services.Stores; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; +using NBitcoin; +using NBitcoin.Secp256k1; using NNostr.Client; namespace BTCPayServer.Plugins.NIP05; +public record ZapperSettings(string ZapperPrivateKey) +{ + public ECPrivKey ZappingKey => NostrExtensions.ParseKey(ZapperPrivateKey); + public ECXOnlyPubKey ZappingPublicKey => ZappingKey.CreateXOnlyPubKey(); + public string ZappingPublicKeyHex => ZappingPublicKey.ToHex(); + +} public class Zapper : IHostedService { record PendingZapEvent(string[] relays, NostrEvent nostrEvent); @@ -23,15 +34,28 @@ public class Zapper : IHostedService private readonly Nip5Controller _nip5Controller; private readonly IMemoryCache _memoryCache; private readonly ILogger _logger; + private readonly SettingsRepository _settingsRepository; private IEventAggregatorSubscription _subscription; private ConcurrentBag _pendingZapEvents = new(); - public Zapper(EventAggregator eventAggregator, Nip5Controller nip5Controller, IMemoryCache memoryCache, ILogger logger) + private async Task GetSettings() + { var result = await _settingsRepository.GetSettingAsync( "Zapper"); + if (result is not null) return result; + result = new ZapperSettings(Convert.ToHexString(RandomUtils.GetBytes(32))); + await _settingsRepository.UpdateSetting(result, "Zapper"); + + return result; + } + + + public Zapper(EventAggregator eventAggregator, + Nip5Controller nip5Controller, IMemoryCache memoryCache, ILogger logger, SettingsRepository settingsRepository, StoreRepository storeRepository) { _eventAggregator = eventAggregator; _nip5Controller = nip5Controller; _memoryCache = memoryCache; _logger = logger; + _settingsRepository = settingsRepository; } public Task StartAsync(CancellationToken cancellationToken) @@ -70,7 +94,27 @@ public class Zapper : IHostedService var tcs = new TaskCompletionSource(); using var c = new NostrClient(new Uri(relay.Key)); await c.ConnectAndWaitUntilConnected(cts.Token); + var pendingOksOnIds = relay.Value.Select(a => a.Id).ToHashSet(); + var subscription = new NostrSubscriptionFilter() + { + Ids = pendingOksOnIds.ToArray() + }; + c.EventsReceived+= (sender, args) => + { + foreach (var nostrEvent in args.events) + { + if (nostrEvent.Id == "zap-confirmation") + { + pendingOksOnIds.Remove(nostrEvent.Id); + if (!pendingOksOnIds.Any()) + { + tcs.SetResult(); + } + } + } + }; + await c.CreateSubscription("zap-confirmations",new []{subscription}, cts.Token); c.OkReceived += (sender, okargs) => { pendingOksOnIds.Remove(okargs.eventId); @@ -87,7 +131,6 @@ public class Zapper : IHostedService } catch (Exception e) { - _logger.LogError(e, $"Error zapping to {relay.Key}"); } })); @@ -131,23 +174,11 @@ public class Zapper : IHostedService } var pmd = (LNURLPayPaymentMethodDetails) pm.GetPaymentMethodDetails(); - var name = pmd.ConsumedLightningAddress.Split("@")[0]; - var settings = await _nip5Controller.Get(name); - if (settings.storeId != arg.Invoice.StoreId) - { - return; - } - - if (string.IsNullOrEmpty(settings.settings.PrivateKey)) - { - return; - } - - var key = NostrExtensions.ParseKey(settings.settings.PrivateKey); - + var settings = await GetSettings(); + var zapRequestEvent = JsonSerializer.Deserialize(zapRequest); var relays = zapRequestEvent.Tags.Where(tag => tag.TagIdentifier == "relays").SelectMany(tag => tag.Data).ToArray(); - + var tags = zapRequestEvent.Tags.Where(a => a.TagIdentifier.Length == 1).ToList(); tags.Add(new() { @@ -165,15 +196,15 @@ public class Zapper : IHostedService { Kind = 9735, CreatedAt = DateTimeOffset.UtcNow, - PublicKey = settings.settings.PubKey, + PublicKey = settings.ZappingPublicKeyHex, Content = zapRequestEvent.Content, Tags = tags }; - await zapReceipt.ComputeIdAndSignAsync(key); - - _pendingZapEvents.Add(new PendingZapEvent(relays.Concat(settings.settings.Relays?? Array.Empty()).Distinct().ToArray(), zapReceipt)); + await zapReceipt.ComputeIdAndSignAsync(settings.ZappingKey); + var userNostrSettings = await _nip5Controller.GetForStore(arg.Invoice.StoreId); + _pendingZapEvents.Add(new PendingZapEvent(relays.Concat(userNostrSettings?.Relays?? Array.Empty()).Distinct().ToArray(), zapReceipt)); } public Task StopAsync(CancellationToken cancellationToken) diff --git a/Plugins/BTCPayServer.Plugins.Prism/SatBreaker.cs b/Plugins/BTCPayServer.Plugins.Prism/SatBreaker.cs index 8047c9d..e489d73 100644 --- a/Plugins/BTCPayServer.Plugins.Prism/SatBreaker.cs +++ b/Plugins/BTCPayServer.Plugins.Prism/SatBreaker.cs @@ -137,7 +137,7 @@ namespace BTCPayServer.Plugins.Prism lnClients.Add(payout.StoreDataId, lnClient); } - if (lnClient is not null) + if (lnClient is not null && proof?.PaymentHash is not null) { var p = await lnClient.GetPayment(proof.PaymentHash, CancellationToken); feePaid = (long) p.Fee.ToUnit(LightMoneyUnit.Satoshi); diff --git a/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayCoinjoinCoinSelector.cs b/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayCoinjoinCoinSelector.cs index 6faf6a8..ee12dd3 100644 --- a/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayCoinjoinCoinSelector.cs +++ b/Plugins/BTCPayServer.Plugins.Wabisabi/BTCPayCoinjoinCoinSelector.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using NBitcoin; +using WalletWasabi.Blockchain.Keys; using WalletWasabi.Blockchain.TransactionOutputs; using WalletWasabi.Crypto.Randomness; using WalletWasabi.Extensions; @@ -161,6 +162,14 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector } solution.Coins.Add(coin); + // we make sure to spend all coins of the same script as it reduces the chance of the user stupidly consolidating later on + var scriptPubKey = coin.ScriptPubKey; + var reusedAddressCoins = remainingCoins.Where(smartCoin => smartCoin.ScriptPubKey == scriptPubKey).ToArray(); + foreach (var reusedAddressCoin in reusedAddressCoins) + { + remainingCoins.Remove(reusedAddressCoin); + solution.Coins.Add(reusedAddressCoin); + } // Loop through the pending payments and handle each payment by subtracting the payment amount from the total value of the selected coins var potentialPayments = remainingPendingPayments @@ -317,8 +326,6 @@ public class SubsetSolution sc.TryGetValue(AnonsetType.Red, out var rcoins); sb.AppendLine( $"Solution total coins:{Coins.Count} R:{rcoins?.Length ?? 0} O:{ocoins?.Length ?? 0} G:{gcoins?.Length ?? 0} AL:{GetAnonLoss(Coins)} total value: {TotalValue} total payments:{TotalPaymentCost}/{TotalPaymentsGross} leftover: {LeftoverValue}"); - sb.AppendLine( - $"Used coins: {string.Join(", ", Coins.Select(coin => coin.Outpoint + " " + coin.Amount.ToString() + " A" + coin.AnonymitySet))}"); if (HandledPayments.Any()) sb.AppendLine($"handled payments: {string.Join(", ", HandledPayments.Select(p => p.Value))} "); return sb.ToString(); diff --git a/Plugins/BTCPayServer.Plugins.Wabisabi/Views/WabisabiStore/UpdateWabisabiStoreSettings.cshtml b/Plugins/BTCPayServer.Plugins.Wabisabi/Views/WabisabiStore/UpdateWabisabiStoreSettings.cshtml index 40abb80..2850245 100644 --- a/Plugins/BTCPayServer.Plugins.Wabisabi/Views/WabisabiStore/UpdateWabisabiStoreSettings.cshtml +++ b/Plugins/BTCPayServer.Plugins.Wabisabi/Views/WabisabiStore/UpdateWabisabiStoreSettings.cshtml @@ -60,7 +60,7 @@ { } } diff --git a/submodules/walletwasabi b/submodules/walletwasabi index d66b482..dfcfd64 160000 --- a/submodules/walletwasabi +++ b/submodules/walletwasabi @@ -1 +1 @@ -Subproject commit d66b482b8883eb9835c901399d8f9d9fd7878add +Subproject commit dfcfd644f431089e3e4548aff7f6e1bba26b6267