mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
wabiupdate
This commit is contained in:
@@ -27,8 +27,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BTCPayServer.Plugins.FixedF
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BTCPayServer.Plugins.LiquidPlus", "Plugins\BTCPayServer.Plugins.LiquidPlus\BTCPayServer.Plugins.LiquidPlus.csproj", "{B4E2ED08-4AD3-4648-8BDB-3107200460B9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BTCPayServer.Plugins.NFC", "Plugins\BTCPayServer.Plugins.NFC\BTCPayServer.Plugins.NFC.csproj", "{71885A5E-1B00-4676-9566-D81AAE37406C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BTCPayServer.Plugins.SideShift", "Plugins\BTCPayServer.Plugins.SideShift\BTCPayServer.Plugins.SideShift.csproj", "{5E1BAA06-7828-47BC-89D6-19C2A78EA427}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BTCPayServer.Plugins.TicketTailor", "Plugins\BTCPayServer.Plugins.TicketTailor\BTCPayServer.Plugins.TicketTailor.csproj", "{7AFC20EB-1696-47D7-8E57-822B05DD18F2}"
|
||||
@@ -151,14 +149,6 @@ Global
|
||||
{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
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Altcoins-Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Altcoins-Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Altcoins-Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{71885A5E-1B00-4676-9566-D81AAE37406C}.Altcoins-Release|Any CPU.Build.0 = Release|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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>10</LangVersion>
|
||||
<LangVersion>11</LangVersion>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
</PropertyGroup>
|
||||
@@ -13,7 +13,7 @@
|
||||
<PropertyGroup>
|
||||
<Product>Wabisabi Coinjoin</Product>
|
||||
<Description>Allows you to integrate your btcpayserver store with coinjoins.</Description>
|
||||
<Version>1.0.55</Version>
|
||||
<Version>1.0.56</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Plugin development properties -->
|
||||
@@ -43,7 +43,7 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NNostr.Client" Version="0.0.34" />
|
||||
<PackageReference Include="NNostr.Client" Version="0.0.37" />
|
||||
<PackageReference Include="WabiSabi" Version="1.0.1.2" />
|
||||
</ItemGroup>
|
||||
<Target Name="DeleteExampleFile" AfterTargets="Publish">
|
||||
|
||||
@@ -15,6 +15,7 @@ using BTCPayServer.Payments.PayJoin;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
@@ -53,7 +54,8 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
public readonly ILogger Logger;
|
||||
public static readonly BlockchainAnalyzer BlockchainAnalyzer = new();
|
||||
|
||||
public BTCPayWallet(WalletRepository walletRepository,
|
||||
public BTCPayWallet(
|
||||
WalletRepository walletRepository,
|
||||
BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
BitcoinLikePayoutHandler bitcoinLikePayoutHandler,
|
||||
BTCPayNetworkJsonSerializerSettings btcPayNetworkJsonSerializerSettings,
|
||||
@@ -66,7 +68,8 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
WabisabiStoreSettings wabisabiStoreSettings,
|
||||
IUTXOLocker utxoLocker,
|
||||
ILoggerFactory loggerFactory,
|
||||
StoreRepository storeRepository)
|
||||
StoreRepository storeRepository,
|
||||
IMemoryCache memoryCache)
|
||||
{
|
||||
KeyChain = keyChain;
|
||||
_walletRepository = walletRepository;
|
||||
@@ -81,6 +84,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
WabisabiStoreSettings = wabisabiStoreSettings;
|
||||
UtxoLocker = utxoLocker;
|
||||
_storeRepository = storeRepository;
|
||||
_memoryCache = memoryCache;
|
||||
Logger = loggerFactory.CreateLogger($"BTCPayWallet_{storeId}");
|
||||
|
||||
}
|
||||
@@ -147,6 +151,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
private IRoundCoinSelector _coinSelector;
|
||||
public Smartifier _smartifier => (KeyChain as BTCPayKeyChain)?.Smartifier;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
public IRoundCoinSelector GetCoinSelector()
|
||||
{
|
||||
@@ -492,7 +497,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
}))}, "utxo");
|
||||
|
||||
}
|
||||
_smartifier.Transactions.AddOrReplace(txHash, Task.FromResult(smartTx));
|
||||
_smartifier.SmartTransactions.AddOrReplace(txHash, Task.FromResult(smartTx));
|
||||
//
|
||||
// var kp = await ExplorerClient.GetMetadataAsync<RootedKeyPath>(DerivationScheme,
|
||||
// WellknownMetadataKeys.AccountKeyPath);
|
||||
@@ -552,6 +557,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
stopwatch.Stop();
|
||||
|
||||
Logger.LogInformation($"Registered coinjoin result for {StoreId} in {stopwatch.Elapsed}");
|
||||
_memoryCache.Remove(WabisabiService.GetCacheKey(StoreId) + "cjhistory");
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -97,7 +97,7 @@ Reputation risks: as the coordinator, the user may be associated with illegal ac
|
||||
else
|
||||
{
|
||||
vm.UriToAdvertise = Request.GetAbsoluteRootUri();
|
||||
TempData["SuccessMessage"] = $"Will create nostr events that point to ${ vm.UriToAdvertise }";
|
||||
TempData["SuccessMessage"] = $"Will create nostr events that point to { vm.UriToAdvertise }";
|
||||
await _wabisabiCoordinatorService.UpdateSettings( vm);
|
||||
return RedirectToAction(nameof(UpdateWabisabiSettings));
|
||||
}
|
||||
|
||||
@@ -195,9 +195,7 @@ public class WabisabiCoordinatorService : PeriodicRunner
|
||||
var coordinatorParameters =
|
||||
new CoordinatorParameters(Path.Combine(_dataDirectories.Value.DataDir, "Plugins", "Coinjoin"));
|
||||
var coinJoinIdStore =
|
||||
CoinJoinIdStore.Create(
|
||||
Path.Combine(coordinatorParameters.ApplicationDataDir, "CcjCoordinator",
|
||||
$"CoinJoins{explorerClient.Network}.txt"), coordinatorParameters.CoinJoinIdStoreFilePath);
|
||||
CoinJoinIdStore.Create( coordinatorParameters.CoinJoinIdStoreFilePath);
|
||||
var coinJoinScriptStore = CoinJoinScriptStore.LoadFromFile(coordinatorParameters.CoinJoinScriptStoreFilePath);
|
||||
var rpc = new BtcPayRpcClient(explorerClient.RPCClient, _memoryCache, explorerClient);
|
||||
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Plugins.Wabisabi;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static string ToSentenceCase(this string str)
|
||||
{
|
||||
return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an existing task from the concurrent dictionary, or adds a new task
|
||||
/// using the specified asynchronous factory method. Concurrent invocations for
|
||||
|
||||
@@ -8,6 +8,7 @@ using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Payments.PayJoin;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
@@ -22,6 +23,7 @@ namespace BTCPayServer.Plugins.Wabisabi;
|
||||
|
||||
public class Smartifier
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly WalletRepository _walletRepository;
|
||||
private readonly ExplorerClient _explorerClient;
|
||||
public DerivationStrategyBase DerivationScheme { get; }
|
||||
@@ -29,10 +31,12 @@ public class Smartifier
|
||||
private readonly IUTXOLocker _utxoLocker;
|
||||
|
||||
public Smartifier(
|
||||
ILogger logger,
|
||||
WalletRepository walletRepository,
|
||||
ExplorerClient explorerClient, DerivationStrategyBase derivationStrategyBase, string storeId,
|
||||
IUTXOLocker utxoLocker, RootedKeyPath accountKeyPath)
|
||||
{
|
||||
_logger = logger;
|
||||
_walletRepository = walletRepository;
|
||||
_explorerClient = explorerClient;
|
||||
DerivationScheme = derivationStrategyBase;
|
||||
@@ -40,10 +44,49 @@ public class Smartifier
|
||||
_utxoLocker = utxoLocker;
|
||||
_accountKeyPath = accountKeyPath;
|
||||
}
|
||||
|
||||
public readonly ConcurrentDictionary<uint256, Task<TransactionInformation>> CachedTransactions = new();
|
||||
public readonly ConcurrentDictionary<uint256, Task<SmartTransaction>> Transactions = new();
|
||||
public readonly ConcurrentDictionary<uint256, Lazy<Task<TransactionInformation>>> TransactionInformations = new();
|
||||
public readonly ConcurrentDictionary<uint256, Task<SmartTransaction>> SmartTransactions = new();
|
||||
public readonly ConcurrentDictionary<OutPoint, Task<SmartCoin>> Coins = new();
|
||||
|
||||
public static async Task<T?> GetOrCreate<T, Y>(ConcurrentDictionary<Y, Lazy<Task<T?>>> collection, Y key, Func<Task<T?>> create, ILogger logger = null)
|
||||
{
|
||||
var lazyTask = new Lazy<Task<T?>>(() => FetchFromServer(create, logger, key));
|
||||
|
||||
// Even if multiple threads provide their own new Lazy instances, only one will be stored.
|
||||
var task = collection.GetOrAdd(key, lazyTask).Value;
|
||||
|
||||
try
|
||||
{
|
||||
return await task;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// If there's an error, remove the lazy task from the dictionary.
|
||||
collection.TryRemove(key, out _);
|
||||
// The error has already been logged inside FetchFromServer.
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<T?> FetchFromServer<T, Y>(Func<Task<T?>> create, ILogger logger, Y key)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await create();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger?.LogError(e, "Error while loading(and caching) {key}", key);
|
||||
throw; // Re-throw the exception so the outer catch can handle it.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<TransactionInformation?> GetTransactionInfo(uint256 hash)
|
||||
{
|
||||
return await GetOrCreate(TransactionInformations , hash, () => _explorerClient.GetTransactionAsync(DerivationScheme, hash), _logger);
|
||||
}
|
||||
|
||||
private readonly RootedKeyPath _accountKeyPath;
|
||||
|
||||
public async Task LoadCoins(List<ReceivedCoin> coins, int current ,
|
||||
@@ -57,15 +100,14 @@ public class Smartifier
|
||||
var txs = coins.Select(data => data.OutPoint.Hash).Distinct();
|
||||
foreach (uint256 tx in txs)
|
||||
{
|
||||
if(!CachedTransactions.ContainsKey(tx))
|
||||
CachedTransactions.TryAdd(tx, _explorerClient.GetTransactionAsync(DerivationScheme, tx));
|
||||
_ =GetTransactionInfo(tx);
|
||||
}
|
||||
|
||||
foreach (var coin in coins)
|
||||
{
|
||||
var tx = await Transactions.GetOrAdd(coin.OutPoint.Hash, async uint256 =>
|
||||
var tx = await SmartTransactions.GetOrAdd(coin.OutPoint.Hash, async uint256 =>
|
||||
{
|
||||
var unsmartTx = await CachedTransactions[coin.OutPoint.Hash];
|
||||
var unsmartTx = await GetTransactionInfo(coin.OutPoint.Hash);
|
||||
if (unsmartTx?.Transaction is null)
|
||||
{
|
||||
return null;
|
||||
@@ -85,17 +127,7 @@ public class Smartifier
|
||||
potentialMatches.TryAdd(matchedInput, potentialMatchesForInput.ToArray());
|
||||
foreach (IndexedTxIn potentialMatchForInput in potentialMatchesForInput)
|
||||
{
|
||||
TransactionInformation ti = null;
|
||||
try
|
||||
{
|
||||
ti = await CachedTransactions.GetOrAdd(potentialMatchForInput.PrevOut.Hash,
|
||||
_explorerClient.GetTransactionAsync(DerivationScheme,
|
||||
potentialMatchForInput.PrevOut.Hash));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CachedTransactions.Remove(potentialMatchForInput.PrevOut.Hash, out _);
|
||||
}
|
||||
var ti = await GetTransactionInfo(potentialMatchForInput.PrevOut.Hash);
|
||||
if (ti is not null)
|
||||
{
|
||||
MatchedOutput found = ti.Outputs.Find(output =>
|
||||
@@ -157,7 +189,6 @@ public class Smartifier
|
||||
var smartCoin = await Coins.GetOrAdd(coin.OutPoint, async point =>
|
||||
{
|
||||
utxoLabels.TryGetValue(coin.OutPoint, out var labels);
|
||||
var unsmartTx = await CachedTransactions[coin.OutPoint.Hash];
|
||||
var pubKey = DerivationScheme.GetChild(coin.KeyPath).GetExtPubKeys().First().PubKey;
|
||||
//if there is no account key path, it most likely means this is a watch only wallet. Fake the key path
|
||||
var kp = _accountKeyPath?.Derive(coin.KeyPath).KeyPath ?? new KeyPath(0,0,0,0,0);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@model WalletWasabi.Backend.Controllers.DiscoveredCoordinator
|
||||
@inject IScopeProvider ScopeProvider
|
||||
<form asp-action="AddCoordinator" method="post" class="card mt-3" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()" permission="@Policies.CanModifyServerSettings">
|
||||
<form asp-action="AddCoordinator" asp-controller="WabisabiStore" method="post" class="card mt-3" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()" permission="@Policies.CanModifyServerSettings">
|
||||
<input type="hidden" asp-for="Description"/>
|
||||
<input type="hidden" asp-for="Name"/>
|
||||
<input type="hidden" asp-for="Uri"/>
|
||||
@@ -19,7 +19,7 @@
|
||||
<p>@Model.Description</p>
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<button name="command" type="submit" class="btn btn-primary btn-lg">Add</button>
|
||||
<button name="command" type="submit" class="btn btn-primary btn-lg">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
|
||||
|
||||
<button type="button" class="btn btn-secondary mt-2" permission="@Policies.CanModifyServerSettings"
|
||||
data-bs-toggle="modal" data-bs-target="#discover-prompt">
|
||||
Add Coordinator
|
||||
</button>
|
||||
@* <button type="button" class="btn btn-secondary mt-2" permission="@Policies.CanModifyServerSettings" *@
|
||||
@* data-bs-toggle="modal" data-bs-target="#discover-prompt"> *@
|
||||
@* Add Coordinator *@
|
||||
@* </button> *@
|
||||
<div class="modal fade" id="discover-prompt" permission="@Policies.CanModifyServerSettings">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@@ -30,7 +30,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content ">
|
||||
<form asp-action="AddCoordinator" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()"
|
||||
<form asp-action="AddCoordinator" asp-controller="WabisabiStore" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()"
|
||||
class="tab-pane fade show active " id="nostr-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
|
||||
|
||||
<div class="modal-body">
|
||||
@@ -45,7 +45,7 @@
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</form>
|
||||
<form asp-action="AddCoordinator" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()"
|
||||
<form asp-action="AddCoordinator" asp-controller="WabisabiStore" asp-route-storeId="@ScopeProvider.GetCurrentStoreId()"
|
||||
class="tab-pane fade" id="manual-tab-pane" role="tabpanel" tabindex="0">
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Client.Models
|
||||
@using BTCPayServer.Common
|
||||
@using BTCPayServer.Plugins.Wabisabi
|
||||
@using BTCPayServer.Security
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using NBitcoin
|
||||
@using WalletWasabi.Blockchain.Analysis
|
||||
@using WalletWasabi.Extensions
|
||||
@using WalletWasabi.WabiSabi.Backend.Rounds
|
||||
@using WalletWasabi.WabiSabi.Client
|
||||
@using WalletWasabi.WabiSabi.Models
|
||||
@model object
|
||||
@inject IScopeProvider ScopeProvider
|
||||
@inject BTCPayServerClient Client
|
||||
@inject WabisabiService WabisabiService;
|
||||
@inject WalletProvider WalletProvider;
|
||||
@inject WabisabiCoordinatorClientInstanceManager WabisabiCoordinatorClientInstanceManager
|
||||
@@ -22,12 +20,6 @@
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@if (!(await ExplorerClientProvider.GetExplorerClient("BTC").GetStatusAsync()).IsFullySynched)
|
||||
{
|
||||
available = false;
|
||||
return;
|
||||
}
|
||||
var storeId = ScopeProvider.GetCurrentStoreId();
|
||||
|
||||
}
|
||||
@@ -57,7 +49,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="widget store-wallet-balance" >
|
||||
<div class="widget store-wallet-balance">
|
||||
<header>
|
||||
<h3>Recent Coinjoins</h3>
|
||||
@if (cjHistory.Any())
|
||||
@@ -89,7 +81,7 @@
|
||||
|
||||
var privacyPercentage = Math.Round(privacy * 100);
|
||||
var colorCoins = coins.GroupBy(coin => coin.CoinColor(wallet.AnonScoreTarget)).ToDictionary(grouping => grouping.Key, grouping => grouping);
|
||||
<div class="widget store-numbers" >
|
||||
<div class="widget store-numbers">
|
||||
|
||||
@if (wallet is { })
|
||||
{
|
||||
@@ -151,35 +143,35 @@
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@{
|
||||
var coinjoined = @coins.CoinJoinInProcess();
|
||||
}
|
||||
@if (coinjoined.Any())
|
||||
{
|
||||
var count = @coins.CoinJoinInProcess().Count();
|
||||
var totalCount = @coins.Count();
|
||||
var sum = @coinjoined.TotalAmount().ToDecimal(MoneyUnit.BTC);
|
||||
var totalSum = @coins.TotalAmount().ToDecimal(MoneyUnit.BTC);
|
||||
var sumPercentage = decimal.Divide(sum, totalSum) * 100;
|
||||
var countPercentage = decimal.Divide(count, totalCount) * 100;
|
||||
|
||||
<div>
|
||||
<h6 class="mb-2">Coins currently joining</h6>
|
||||
<div class="progress mb-2 position-relative" style="height: 2rem;">
|
||||
<div class="w-100 text-center position-absolute bg-transparent progress-bar h-100">@count </div>
|
||||
<div class="progress-bar bg-info progress-bar-striped progress-bar-animated w-100" role="progressbar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-2">Value currently joining</h6>
|
||||
<div class="progress mb-2 position-relative" style="height: 2rem;">
|
||||
<div class="w-100 text-center position-absolute bg-transparent progress-bar h-100">@sum BTC</div>
|
||||
<div class="progress-bar bg-info progress-bar-striped progress-bar-animated w-100" role="progressbar"></div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@* @{ *@
|
||||
@* var coinjoined = @coins.CoinJoinInProcess(); *@
|
||||
@* } *@
|
||||
@* @if (coinjoined.Any()) *@
|
||||
@* { *@
|
||||
@* var count = @coins.CoinJoinInProcess().Count(); *@
|
||||
@* var totalCount = @coins.Count(); *@
|
||||
@* var sum = @coinjoined.TotalAmount().ToDecimal(MoneyUnit.BTC); *@
|
||||
@* var totalSum = @coins.TotalAmount().ToDecimal(MoneyUnit.BTC); *@
|
||||
@* var sumPercentage = decimal.Divide(sum, totalSum) * 100; *@
|
||||
@* var countPercentage = decimal.Divide(count, totalCount) * 100; *@
|
||||
@* *@
|
||||
@* <div> *@
|
||||
@* <h6 class="mb-2">Coins currently joining</h6> *@
|
||||
@* <div class="progress mb-2 position-relative" style="height: 2rem;"> *@
|
||||
@* <div class="w-100 text-center position-absolute bg-transparent progress-bar h-100">@count </div> *@
|
||||
@* <div class="progress-bar bg-info progress-bar-striped progress-bar-animated w-100" role="progressbar"></div> *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
@* <div> *@
|
||||
@* <h6 class="mb-2">Value currently joining</h6> *@
|
||||
@* <div class="progress mb-2 position-relative" style="height: 2rem;"> *@
|
||||
@* <div class="w-100 text-center position-absolute bg-transparent progress-bar h-100">@sum BTC</div> *@
|
||||
@* <div class="progress-bar bg-info progress-bar-striped progress-bar-animated w-100" role="progressbar"></div> *@
|
||||
@* *@
|
||||
@* *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
@* } *@
|
||||
|
||||
|
||||
<!-- Modal -->
|
||||
@@ -272,7 +264,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group list-group-flush mb-2">
|
||||
<div class="list-group list-group-flush mt-4 mb-3">
|
||||
<h5 class="list-group-item-heading text-muted">Enabled coordinators</h5>
|
||||
|
||||
@{
|
||||
@@ -282,42 +274,172 @@
|
||||
{
|
||||
continue;
|
||||
}
|
||||
<div class="list-group-item">
|
||||
<h6>@coordinator.CoordinatorDisplayName</h6>
|
||||
<div class="row ">
|
||||
<span class="text-muted col-sm-12 col-xxl-9 p-0 text-break">
|
||||
@coordinator.Coordinator
|
||||
</span>
|
||||
|
||||
@if (!coordinator.WasabiCoordinatorStatusFetcher.Connected)
|
||||
RoundState currentRound = null;
|
||||
CoinJoinTracker tracker = null;
|
||||
if (coordinator.CoinJoinManager.TrackedCoinJoins?.TryGetValue(wallet.WalletName, out tracker) is true &&
|
||||
tracker?.CoinJoinClient?.CurrentRoundId is { } &&
|
||||
tracker?.CoinJoinClient?.RoundStatusUpdater?.RoundStates?.TryGetValue(tracker?.CoinJoinClient?.CurrentRoundId, out currentRound) is true)
|
||||
{
|
||||
}
|
||||
var statusMsg = coordinator.WasabiCoordinatorStatusFetcher.Connected ? $"Connected to {(coordinator.Coordinator?.ToString() ?? "local")}" : $"Not connected to {(coordinator.Coordinator?.ToString() ?? "local")}";
|
||||
<div class="list-group-item">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3" data-bs-toggle="tooltip" title="@statusMsg">
|
||||
<span class="btcpay-status btcpay-status--@(coordinator.WasabiCoordinatorStatusFetcher.Connected ? "enabled" : "disabled")"></span>
|
||||
<h6>@coordinator.CoordinatorDisplayName</h6>
|
||||
</div>
|
||||
@if(currentRound is not null)
|
||||
{
|
||||
<p class="text-danger mb-0 col-sm-12 col-xxl-3 p-0 text-break">Not connected</p>
|
||||
}
|
||||
else
|
||||
<div class="timer cursor-pointer" data-bs-toggle="collapse" data-bs-target="#cj-@currentRound.Id">
|
||||
<span class="spinner-border spinner-border-sm" role="status">
|
||||
<span class="visually-hidden"></span>
|
||||
</span>
|
||||
<span class="h6">Mixing</span>
|
||||
<vc:icon symbol="caret-down" />
|
||||
</div>
|
||||
}else if( coordinator.WasabiCoordinatorStatusFetcher.Connected)
|
||||
{
|
||||
<p class="text-success mb-0 col-sm-12 col-xxl-3 p-0 text-break">Connected</p>
|
||||
|
||||
<span class="h6">Idle</span>
|
||||
}
|
||||
</div>
|
||||
@{
|
||||
|
||||
if (coordinator.CoinPrison is not null)
|
||||
{
|
||||
|
||||
var bannedCoins = coins.Where(coin => coordinator.CoinPrison.TryGetOrRemoveBannedCoin(coin.Outpoint, out _));
|
||||
var bannedCoins = coins.Where(coin => coordinator.CoinPrison.TryGetOrRemoveBannedCoin(coin.Outpoint, out _));
|
||||
@if (bannedCoins.Any())
|
||||
{
|
||||
<div>
|
||||
<h6 class="mb-2">Coins currently banned (for disrupting rounds)</h6>
|
||||
<div class="progress mb-2 position-relative" style="height: 2rem;">
|
||||
<div class="w-100 text-center position-absolute bg-transparent progress-bar h-100">@bannedCoins.Count() </div>
|
||||
<div class="progress-bar bg-danger w-100" role="progressbar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-muted">@bannedCoins.Count() banned coins(for disrupting rounds)</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (currentRound is not null)
|
||||
{
|
||||
<div class="collapse table-responsive @(enabledSettings.Count() ==1? "show": "")" id="cj-@currentRound.Id">
|
||||
<table class="table ">
|
||||
<tr>
|
||||
<th scope="row">Status</th>
|
||||
<td class="text-truncate">@currentRound.Phase.ToString().ToSentenceCase()</td>
|
||||
</tr><tr>
|
||||
<th scope="row">Round id</th>
|
||||
<td class="text-truncate" style="max-width: 200px" title="@currentRound.Id.ToString()">@currentRound.Id.ToString()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Mining feerate</th>
|
||||
<td >@currentRound.CoinjoinState.Parameters.MiningFeeRate.ToString()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Coinjoin total inputs</th>
|
||||
<td >@currentRound.CoinjoinState.Inputs.Count() inputs (@currentRound.CoinjoinState.Inputs.Sum(coin => coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC)</td>
|
||||
</tr>
|
||||
@if (!tracker.CoinJoinClient.CoinsToRegister.IsEmpty)
|
||||
{
|
||||
<tr>
|
||||
<th scope="row">Your inputs</th>
|
||||
<td class="row" >
|
||||
<span class="w-100">Registered @tracker.CoinJoinClient.CoinsInCriticalPhase.Count() inputs (@tracker.CoinJoinClient.CoinsInCriticalPhase.Sum(coin => coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC) / @tracker.CoinJoinClient.CoinsToRegister.Count() inputs (@tracker.CoinJoinClient.CoinsToRegister.Sum(coin => coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC) </span>
|
||||
@if (tracker.BannedCoins.Any())
|
||||
{
|
||||
<span class="w-100 text-danger">but got @tracker.BannedCoins.Count() inputs (@tracker.BannedCoins.Sum(coin => coin.Coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC) banned</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
@if (currentRound.Phase >= Phase.OutputRegistration)
|
||||
{
|
||||
<tr>
|
||||
<th scope="row">Coinjoin total outputs</th>
|
||||
<td >@currentRound.CoinjoinState.Outputs.Count() outputs (@currentRound.CoinjoinState.Outputs.Sum(coin => coin.Value.ToDecimal(MoneyUnit.BTC)) BTC)</td>
|
||||
</tr>
|
||||
if (tracker.CoinJoinClient.OutputTxOuts is { } outputs)
|
||||
{
|
||||
<tr>
|
||||
<th scope="row">Your outputs</th>
|
||||
<td >@outputs.outputTxOuts.Count() outputs (@outputs.outputTxOuts.Sum(coin => coin.Value.ToDecimal(MoneyUnit.BTC)) BTC, @outputs.batchedPayments.Count() batched payments)</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
@* <div class="collapse table-responsive" id="cj-@currentRound.Id"> *@
|
||||
@* *@
|
||||
@* <dl> *@
|
||||
@* <div class="d-flex flex-wrap align-items-center gap-2"> *@
|
||||
@* <dt class="w-100px"> *@
|
||||
@* Status *@
|
||||
@* </dt> *@
|
||||
@* <dd> *@
|
||||
@* @currentRound.Phase.ToString().ToSentenceCase() *@
|
||||
@* </dd> *@
|
||||
@* </div> *@
|
||||
@* <div class="d-flex flex-wrap align-items-center gap-2"> *@
|
||||
@* <dt class="w-100px"> *@
|
||||
@* Round ID *@
|
||||
@* </dt> *@
|
||||
@* <dd> *@
|
||||
@* @currentRound.Id.ToString() *@
|
||||
@* </dd> *@
|
||||
@* </div> *@
|
||||
@* <div class="d-flex flex-wrap align-items-center gap-2"> *@
|
||||
@* <dt class="w-100px"> *@
|
||||
@* Mining feerate *@
|
||||
@* </dt> *@
|
||||
@* <dd> *@
|
||||
@* @currentRound.CoinjoinState.Parameters.MiningFeeRate.ToString() *@
|
||||
@* </dd> *@
|
||||
@* </div> *@
|
||||
@* <div class="d-flex flex-wrap align-items-center gap-2"> *@
|
||||
@* <dt class="w-100px"> *@
|
||||
@* Coinjoin total inputs *@
|
||||
@* </dt> *@
|
||||
@* <dd> *@
|
||||
@* @currentRound.CoinjoinState.Inputs.Count() inputs (@currentRound.CoinjoinState.Inputs.Sum(coin => coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC) *@
|
||||
@* </dd> *@
|
||||
@* </div> *@
|
||||
@* *@
|
||||
@* *@
|
||||
@* @if (!tracker.CoinJoinClient.CoinsToRegister.IsEmpty) *@
|
||||
@* { *@
|
||||
@* <div class="d-flex flex-wrap align-items-center gap-2"> *@
|
||||
@* <dt class="w-100px">Your inputs</dt> *@
|
||||
@* <dd> *@
|
||||
@* <span class="w-100">Registered @tracker.CoinJoinClient.CoinsInCriticalPhase.Count() inputs (@tracker.CoinJoinClient.CoinsInCriticalPhase.Sum(coin => coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC) / @tracker.CoinJoinClient.CoinsToRegister.Count() inputs (@tracker.CoinJoinClient.CoinsToRegister.Sum(coin => coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC) </span> *@
|
||||
@* @if (tracker.BannedCoins.Any()) *@
|
||||
@* { *@
|
||||
@* <span class="w-100 text-danger">but got @tracker.BannedCoins.Count() inputs (@tracker.BannedCoins.Sum(coin => coin.Coin.Amount.ToDecimal(MoneyUnit.BTC)) BTC) banned</span> *@
|
||||
@* } *@
|
||||
@* </dd> *@
|
||||
@* </div> *@
|
||||
@* } *@
|
||||
@* *@
|
||||
@* @if (currentRound.Phase >= Phase.OutputRegistration) *@
|
||||
@* { *@
|
||||
@* <div class="d-flex flex-wrap align-items-center gap-2"> *@
|
||||
@* <dt class="w-100px">Coinjoin total outputs</dt> *@
|
||||
@* <dd> *@
|
||||
@* @currentRound.CoinjoinState.Outputs.Count() outputs (@currentRound.CoinjoinState.Outputs.Sum(coin => coin.Value.ToDecimal(MoneyUnit.BTC)) BTC) *@
|
||||
@* </dd> *@
|
||||
@* </div> *@
|
||||
@* if (tracker.CoinJoinClient.OutputTxOuts is { } outputs) *@
|
||||
@* { *@
|
||||
@* <div class="d-flex flex-wrap align-items-center gap-2"> *@
|
||||
@* <dt class="w-100px">>Your outputs</dt> *@
|
||||
@* <dd> *@
|
||||
@* @outputs.outputTxOuts.Count() outputs (@outputs.outputTxOuts.Sum(coin => coin.Value.ToDecimal(MoneyUnit.BTC)) BTC, @outputs.batchedPayments.Count() batched payments) *@
|
||||
@* </dd> *@
|
||||
@* </div> *@
|
||||
@* } *@
|
||||
@* } *@
|
||||
@* </dl> *@
|
||||
@* *@
|
||||
@* </div> *@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -326,8 +448,6 @@
|
||||
<button type="button" class="btn btn-text p-1" data-bs-toggle="modal" data-bs-target="#coins">
|
||||
View coins
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
@using WalletWasabi.Backend.Controllers
|
||||
@using BTCPayServer.Plugins.Wabisabi
|
||||
@model WalletWasabi.Backend.Controllers.WabisabiCoordinatorSettings
|
||||
|
||||
@@ -8,9 +7,19 @@
|
||||
ViewData["NavPartialName"] = "../UIServer/_Nav";
|
||||
}
|
||||
|
||||
<h2 class="mb-4">Coinjoin coordinator configuration</h2>
|
||||
|
||||
<form method="post">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h3 class="mb-0">
|
||||
<span>Coinjoin coordinator</span>
|
||||
<a href="https://docs.btcpayserver.org/Wabisabi" target="_blank" rel="noreferrer noopener" title="More information...">
|
||||
<vc:icon symbol="info"/>
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<button name="command" type="submit" value="save" class="btn btn-primary mt-3 mt-sm-0">Save</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xxl-constrain col-xl-8">
|
||||
<div class="form-group form-check">
|
||||
@@ -36,9 +45,8 @@
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<div class="col-xxl-constrain col-xl-8">
|
||||
|
||||
<div class="col-xxl-constrain col-xl-4">
|
||||
<h3 class="mb-3">Publish to Nostr </h3>
|
||||
<div class="form-group ">
|
||||
<label asp-for="NostrRelay" class="form-label">Nostr Relay</label>
|
||||
@@ -68,7 +76,6 @@
|
||||
<p class=" alert alert-warning" style="white-space: pre-line">
|
||||
@WabisabiCoordinatorConfigController.OurDisclaimer
|
||||
</p>
|
||||
<button name="command" type="submit" value="save" class="btn btn-primary mt-2">Save</button>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
|
||||
@using BTCPayServer.Components
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Views.Stores
|
||||
@using BTCPayServer.Components
|
||||
@using BTCPayServer
|
||||
@model BTCPayServer.Plugins.Wabisabi.CoinjoinsViewModel
|
||||
@{
|
||||
ViewData.SetActivePage(StoreNavPages.Plugins);
|
||||
var storeId = Context.GetCurrentStoreId();
|
||||
ViewData.SetActivePage("CoinjoinHistory", "Coinjoin", "Coinjoin History", storeId);
|
||||
}
|
||||
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h3 class="mb-0">Coinjoin History</h3>
|
||||
<h3 class="mb-0">
|
||||
<span>@ViewData["Title"]</span>
|
||||
<a href="https://docs.btcpayserver.org/Wabisabi" target="_blank" rel="noreferrer noopener" title="More information...">
|
||||
<vc:icon symbol="info"/>
|
||||
</a>
|
||||
</h3>
|
||||
<a asp-action="UpdateWabisabiStoreSettings" asp-route-storeId="@storeId" class="btn btn-primary mt-3 mt-sm-0" role="button">
|
||||
<span class="fa fa-settings"></span>
|
||||
Settings
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<partial name="Wabisabi/CoinjoinHistoryTable" model="Model.Coinjoins.ToList()" />
|
||||
|
||||
<partial name="Wabisabi/CoinjoinHistoryTable" model="Model.Coinjoins.ToList()"/>
|
||||
<vc:pager view-model="Model"></vc:pager>
|
||||
@@ -17,9 +17,7 @@
|
||||
@inject BTCPayServerOptions BtcPayServerOptions
|
||||
@{
|
||||
var storeId = _scopeProvider.GetCurrentStoreId();
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData["NavPartialName"] = "../UIStores/_Nav";
|
||||
ViewData.SetActivePage("Plugins", "BTCPayServer.Views.Stores.StoreNavPages", "Wabisabi coinjoin support", storeId);
|
||||
ViewData.SetActivePage("CoinjoinSettings", "Coinjoin", "Coinjoin settings", storeId);
|
||||
var userid = Context.User.Claims.Single(claim => claim.Type == ClaimTypes.NameIdentifier).Value;
|
||||
var anyEnabled = Model.Settings.Any(settings => settings.Enabled);
|
||||
ScriptPubKeyType? scriptType;
|
||||
@@ -34,28 +32,45 @@
|
||||
.Select(pair => new SelectListItem(pair.Value.s.StoreName, pair.Key, Model.MixToOtherWallet == pair.Key)).Prepend(new SelectListItem("None", ""));
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="d-flex">
|
||||
<h2 class="">Coinjoin configuration</h2>
|
||||
<a href="https://github.com/Kukks/BTCPayServerPlugins/blob/master/Plugins/BTCPayServer.Plugins.Wabisabi/readme.md" class="ms-1" target="_blank" rel="noreferrer noopener">
|
||||
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
|
||||
|
||||
<form method="post">
|
||||
|
||||
|
||||
<partial name="_StatusMessage"/>
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h3 class="mb-0">
|
||||
<span>@ViewData["Title"]</span>
|
||||
<a href="https://docs.btcpayserver.org/Wabisabi" target="_blank" rel="noreferrer noopener" title="More information...">
|
||||
<vc:icon symbol="info"/>
|
||||
</a>
|
||||
</h3>
|
||||
<div>
|
||||
|
||||
<button name="command" type="submit" value="save" class="btn btn-primary mt-3 mt-sm-0">Save</button>
|
||||
<a asp-action="ListCoinjoins" asp-route-storeId="@storeId" class="btn btn-secondary mt-3 mt-sm-0" role="button">
|
||||
Coinjoin History
|
||||
</a>
|
||||
<button type="button" class="btn btn-secondary mt-3 mt-sm-0" permission="@Policies.CanModifyServerSettings"
|
||||
data-bs-toggle="modal" data-bs-target="#discover-prompt">
|
||||
Add Coordinator
|
||||
</button>
|
||||
<a asp-controller="WabisabiCoordinatorConfig" asp-action="UpdateWabisabiSettings" class="btn btn-secondary mt-3 mt-sm-0" permission="@Policies.CanModifyServerSettings">Coordinator</a>
|
||||
@* <a class="btn btn-secondary mt-3 mt-sm-0" href="https://gist.github.com/nopara73/bb17e89d7dc9af536ca41f50f705d329" rel="noreferrer noopener" target="_blank">Enable Discreet payments - Coming soon</a> *@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<form method="post">
|
||||
@{
|
||||
if (BtcPayServerOptions.SocksEndpoint is null)
|
||||
{
|
||||
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
||||
<vc:icon symbol="warning"/>
|
||||
<span class="ms-3">TOR is not configured on this BTCPay Server instance. All communication will be over clearnet and therefore not private!</span>
|
||||
</div>
|
||||
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
||||
<vc:icon symbol="warning"/>
|
||||
<span class="ms-3">TOR is not configured on this BTCPay Server instance. All communication will be over clearnet and therefore not private!</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
var wallet = await WalletProvider.GetWalletAsync(storeId);
|
||||
if (wallet is BTCPayWallet)
|
||||
{
|
||||
|
||||
@if (!((BTCPayKeyChain) wallet.KeyChain).KeysAvailable)
|
||||
{
|
||||
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
||||
@@ -217,7 +232,7 @@
|
||||
|
||||
<span class="text-muted">@coordinator.Coordinator</span>
|
||||
<div>
|
||||
<div>@(!coordinator.WasabiCoordinatorStatusFetcher.Connected? "Coordinator Status: Not connected": "Coordinator Status: Connected")</div>
|
||||
<div>@(!coordinator.WasabiCoordinatorStatusFetcher.Connected ? "Coordinator Status: Not connected" : "Coordinator Status: Connected")</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(coordinator.Description))
|
||||
{
|
||||
@@ -303,7 +318,7 @@
|
||||
By enabling this coordinator, you agree to their terms and conditions.
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@{
|
||||
var canEnable = coordinator.WasabiCoordinatorStatusFetcher.Connected && coordinator.RoundStateUpdater.AnyRound;
|
||||
@@ -346,15 +361,10 @@
|
||||
}
|
||||
|
||||
|
||||
<button name="command" type="submit" value="save" class="btn btn-primary mt-2">Save</button>
|
||||
<a asp-controller="WabisabiStore" asp-action="ListCoinjoins" class="btn btn-secondary mt-2" asp-route-storeId="@storeId">Coinjoins</a>
|
||||
</form>
|
||||
|
||||
|
||||
<a asp-controller="WabisabiCoordinatorConfig" asp-action="UpdateWabisabiSettings" class="btn btn-secondary mt-2" permission="@Policies.CanModifyServerSettings">Coordinator runner</a>
|
||||
|
||||
<partial name="Wabisabi/AddCoordinatorPrompt" model="@(new DiscoveredCoordinator())"/>
|
||||
<a class="btn btn-secondary mt-2" href="https://gist.github.com/nopara73/bb17e89d7dc9af536ca41f50f705d329" rel="noreferrer noopener" target="_blank">Enable Discreet payments - Coming soon</a>
|
||||
|
||||
|
||||
@section PageFootContent {
|
||||
|
||||
@@ -21,7 +21,6 @@ using WalletWasabi.WabiSabi.Client.RoundStateAwaiters;
|
||||
using WalletWasabi.WabiSabi.Client.StatusChangedEvents;
|
||||
using WalletWasabi.Wallets;
|
||||
using WalletWasabi.WebClients.Wasabi;
|
||||
using HttpClientFactory = WalletWasabi.WebClients.Wasabi.HttpClientFactory;
|
||||
|
||||
namespace BTCPayServer.Plugins.Wabisabi;
|
||||
|
||||
@@ -137,7 +136,7 @@ public class WabisabiCoordinatorClientInstance
|
||||
public Uri Coordinator { get; set; }
|
||||
public WalletProvider WalletProvider { get; }
|
||||
public string TermsConditions { get; set; }
|
||||
public HttpClientFactory WasabiHttpClientFactory { get; set; }
|
||||
public WasabiHttpClientFactory WasabiHttpClientFactory { get; set; }
|
||||
public RoundStateUpdater RoundStateUpdater { get; set; }
|
||||
public CoinPrison CoinPrison { get; private set; }
|
||||
public WasabiCoordinatorStatusFetcher WasabiCoordinatorStatusFetcher { get; set; }
|
||||
@@ -176,7 +175,7 @@ public class WabisabiCoordinatorClientInstance
|
||||
}
|
||||
else
|
||||
{
|
||||
WasabiHttpClientFactory = new HttpClientFactory(torEndpoint, () => Coordinator);
|
||||
WasabiHttpClientFactory = new WasabiHttpClientFactory(torEndpoint, () => Coordinator);
|
||||
var roundStateUpdaterCircuit = new PersonCircuit();
|
||||
var roundStateUpdaterHttpClient =
|
||||
WasabiHttpClientFactory.NewHttpClient(Mode.SingleCircuitPerLifetime, roundStateUpdaterCircuit);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
@@ -20,7 +21,7 @@ public class WabisabiPlugin : BaseBTCPayServerPlugin
|
||||
{
|
||||
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
|
||||
{
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.11.0" }
|
||||
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.11.5" }
|
||||
};
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
@@ -140,3 +141,4 @@ public class WabisabiPlugin : BaseBTCPayServerPlugin
|
||||
base.Execute(applicationBuilder, applicationBuilderApplicationServices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -33,7 +34,7 @@ namespace BTCPayServer.Plugins.Wabisabi
|
||||
_memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
private string GetCacheKey(string storeId)
|
||||
public static string GetCacheKey(string storeId)
|
||||
{
|
||||
return $"{nameof(WabisabiStoreSettings)}-{storeId}";
|
||||
}
|
||||
@@ -76,7 +77,7 @@ namespace BTCPayServer.Plugins.Wabisabi
|
||||
_walletProvider.LoadedWallets.TryGetValue(storeId, out var walletTask);
|
||||
if (walletTask != null)
|
||||
{
|
||||
var wallet = await walletTask;
|
||||
var wallet = await walletTask.Value;
|
||||
await _coordinatorClientInstanceManager.StopWallet(wallet, setting.Coordinator);
|
||||
}
|
||||
}
|
||||
@@ -136,15 +137,29 @@ namespace BTCPayServer.Plugins.Wabisabi
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<BTCPayWallet.CoinjoinData>> GetCoinjoinHistory(string storeId)
|
||||
public async Task<List<BTCPayWallet.CoinjoinData>> GetCoinjoinHistory(string storeId, bool force = false)
|
||||
{
|
||||
return (await _walletRepository.GetWalletObjects(
|
||||
new GetWalletObjectsQuery(new WalletId(storeId, "BTC"))
|
||||
{
|
||||
Type = "coinjoin"
|
||||
})).Values.Where(data => !string.IsNullOrEmpty(data.Data))
|
||||
.Select(data => JObject.Parse(data.Data).ToObject<BTCPayWallet.CoinjoinData>())
|
||||
.OrderByDescending(tuple => tuple.Timestamp).ToList();
|
||||
var k = GetCacheKey(storeId) + "cjhistory";
|
||||
if (force)
|
||||
{
|
||||
_memoryCache.Remove(k);
|
||||
}
|
||||
|
||||
return await _memoryCache.GetOrCreateAsync(k, async entry =>
|
||||
{
|
||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
|
||||
var result = (await _walletRepository.GetWalletObjects(
|
||||
new GetWalletObjectsQuery(new WalletId(storeId, "BTC"))
|
||||
{
|
||||
Type = "coinjoin"
|
||||
})).Values.Where(data => !string.IsNullOrEmpty(data.Data))
|
||||
.Select(data => JObject.Parse(data.Data).ToObject<BTCPayWallet.CoinjoinData>())
|
||||
.OrderByDescending(tuple => tuple.Timestamp).ToList();
|
||||
entry.Value = result;
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Payments.PayJoin;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBitcoin;
|
||||
@@ -57,7 +58,7 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
_networkProvider = networkProvider;
|
||||
}
|
||||
|
||||
public readonly ConcurrentDictionary<string, Task<IWallet?>> LoadedWallets = new();
|
||||
public readonly ConcurrentDictionary<string, Lazy<Task<IWallet>>> LoadedWallets = new();
|
||||
|
||||
public class WalletUnloadEventArgs : EventArgs
|
||||
{
|
||||
@@ -73,7 +74,7 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
public async Task<IWallet?> GetWalletAsync(string name)
|
||||
{
|
||||
await initialLoad.Task;
|
||||
return await LoadedWallets.GetOrAddAsync(name, async s =>
|
||||
return await Smartifier.GetOrCreate(LoadedWallets, name, async () =>
|
||||
{
|
||||
if (!_cachedSettings.TryGetValue(name, out var wabisabiStoreSettings))
|
||||
{
|
||||
@@ -101,7 +102,7 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
var accountKeyPath2 = await explorerClient.GetMetadataAsync<RootedKeyPath>(derivationStrategy,
|
||||
WellknownMetadataKeys.AccountKeyPath);
|
||||
accountKeyPath = accountKeyPath2 ?? accountKeyPath;
|
||||
var smartifier = new Smartifier(_serviceProvider.GetRequiredService<WalletRepository>(),
|
||||
var smartifier = new Smartifier(_logger,_serviceProvider.GetRequiredService<WalletRepository>(),
|
||||
explorerClient, derivationStrategy, name, UtxoLocker, accountKeyPath);
|
||||
if (masterKey is null || accountKey is null || accountKeyPath is null)
|
||||
{
|
||||
@@ -112,7 +113,7 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
}
|
||||
else
|
||||
{
|
||||
var smartifier = new Smartifier(_serviceProvider.GetRequiredService<WalletRepository>(), explorerClient,
|
||||
var smartifier = new Smartifier(_logger,_serviceProvider.GetRequiredService<WalletRepository>(), explorerClient,
|
||||
derivationStrategy, name, UtxoLocker, accountKeyPath);
|
||||
keychain = new BTCPayKeyChain(explorerClient, derivationStrategy, null, null, smartifier);
|
||||
}
|
||||
@@ -127,9 +128,11 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
_serviceProvider.GetRequiredService<PullPaymentHostedService>(),derivationStrategy, explorerClient, keychain,
|
||||
name, wabisabiStoreSettings, UtxoLocker,
|
||||
_loggerFactory,
|
||||
_serviceProvider.GetRequiredService<StoreRepository>());
|
||||
_serviceProvider.GetRequiredService<StoreRepository>(),
|
||||
_serviceProvider.GetRequiredService<IMemoryCache>()
|
||||
);
|
||||
|
||||
});
|
||||
}, _logger);
|
||||
|
||||
}
|
||||
|
||||
@@ -231,7 +234,7 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
LoadedWallets.TryRemove(name, out var walletTask);
|
||||
if (walletTask != null)
|
||||
{
|
||||
var wallet = await walletTask;
|
||||
var wallet = await walletTask.Value;
|
||||
WalletUnloaded?.Invoke(this, new WalletUnloadEventArgs(wallet));
|
||||
}
|
||||
}
|
||||
@@ -247,7 +250,7 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
{
|
||||
|
||||
_cachedSettings.AddOrReplace(storeId, wabisabiSettings);
|
||||
var btcpayWalet = (BTCPayWallet) await existingWallet;
|
||||
var btcpayWalet = (BTCPayWallet) await existingWallet.Value;
|
||||
if (btcpayWalet is null)
|
||||
{
|
||||
|
||||
|
||||
Submodule submodules/btcpayserver updated: cdffe9b355...25af9c4227
Submodule submodules/walletwasabi updated: 17e053ce5f...84f310060d
Reference in New Issue
Block a user