mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2026-01-31 13:34:52 +01:00
improve
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=b4e2ed08_002D4ad3_002D4648_002D8bdb_002D3107200460b9_0023BTCPayServer_002EPlugins_002ELiquidPlus/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=b4e2ed08_002D4ad3_002D4648_002D8bdb_002D3107200460b9_0023BTCPayServer_002EPlugins_002ELiquidPlus/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nostr/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -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<IActionResult> Edit(string storeId)
|
||||
{
|
||||
var settings = await _storeRepository.GetSettingAsync<Nip5StoreSettings>(storeId, "NIP05");
|
||||
var settings = await GetForStore(storeId);
|
||||
return View(settings ?? new());
|
||||
}
|
||||
[NonAction]
|
||||
public async Task<Nip5StoreSettings?> GetForStore(string storeId)
|
||||
{
|
||||
return await _memoryCache.GetOrCreateAsync("NIP05_" + storeId, async entry => await _storeRepository.GetSettingAsync<Nip5StoreSettings>(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<IActionResult> Edit(string storeId, Nip5StoreSettings settings, string command)
|
||||
{
|
||||
|
||||
var existingSettings = await GetForStore(storeId);
|
||||
if (command == "remove")
|
||||
{
|
||||
var settingss = await _storeRepository.GetSettingAsync<Nip5StoreSettings>(storeId, "NIP05");
|
||||
if (settingss is not null)
|
||||
if (existingSettings is not null)
|
||||
{
|
||||
await _storeRepository.UpdateSetting<Nip5StoreSettings>(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<Nip5StoreSettings>(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]
|
||||
|
||||
@@ -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<Zapper> _logger;
|
||||
private readonly SettingsRepository _settingsRepository;
|
||||
private IEventAggregatorSubscription _subscription;
|
||||
private ConcurrentBag<PendingZapEvent> _pendingZapEvents = new();
|
||||
|
||||
public Zapper(EventAggregator eventAggregator, Nip5Controller nip5Controller, IMemoryCache memoryCache, ILogger<Zapper> logger)
|
||||
private async Task<ZapperSettings> GetSettings()
|
||||
{ var result = await _settingsRepository.GetSettingAsync<ZapperSettings>( "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<Zapper> 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<NostrEvent>(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<string>()).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<string>()).Distinct().ToArray(), zapReceipt));
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
{
|
||||
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
||||
<vc:icon symbol="warning"/>
|
||||
<span class="ms-3">This wallet is either not a hot wallet, or enabled in yout store settings and will not be able to participate in coinjoins.</span>
|
||||
<span class="ms-3">This wallet is either not a hot wallet, or enabled in your store settings and will not be able to participate in coinjoins.</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
Submodule submodules/walletwasabi updated: d66b482b88...dfcfd644f4
Reference in New Issue
Block a user