mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-20 13:34:37 +01:00
Payjoin label fixes (#3986)
* Payjoin label fixes * When a payjoin label was applied, coin selection filter would not work * When a payjoin happened with a receive address wallet, the payjoin label was not applied * Coin selection shows when a utxo is currently reserved for a payjoin. Applies both to UI and to GF API * remove reserved label * Update BTCPayServer/Payments/PayJoin/PayJoinEndpointController.cs
This commit is contained in:
parent
2e6246e385
commit
bec888da19
11 changed files with 82 additions and 71 deletions
13
BTCPayServer.Abstractions/Contracts/IUTXOLocker.cs
Normal file
13
BTCPayServer.Abstractions/Contracts/IUTXOLocker.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Payments.PayJoin;
|
||||
|
||||
public interface IUTXOLocker
|
||||
{
|
||||
Task<bool> TryLock(OutPoint outpoint);
|
||||
Task<bool> TryUnlock(params OutPoint[] outPoints);
|
||||
Task<bool> TryLockInputs(OutPoint[] outPoints);
|
||||
Task<HashSet<OutPoint>> FindLocks(OutPoint[] outpoints);
|
||||
}
|
|
@ -69,7 +69,7 @@ namespace BTCPayServer.Tests
|
|||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var network = tester.NetworkProvider.GetNetwork<BTCPayNetwork>("BTC");
|
||||
var repo = tester.PayTester.GetService<PayJoinRepository>();
|
||||
var repo = tester.PayTester.GetService<UTXOLocker>();
|
||||
var outpoint = RandomOutpoint();
|
||||
|
||||
// Should not be locked
|
||||
|
@ -166,7 +166,7 @@ namespace BTCPayServer.Tests
|
|||
using var tester = CreateServerTester();
|
||||
await tester.StartAsync();
|
||||
var broadcaster = tester.PayTester.GetService<DelayedTransactionBroadcaster>();
|
||||
var payjoinRepository = tester.PayTester.GetService<PayJoinRepository>();
|
||||
var payjoinRepository = tester.PayTester.GetService<UTXOLocker>();
|
||||
broadcaster.Disable();
|
||||
var network = tester.NetworkProvider.GetNetwork<BTCPayNetwork>("BTC");
|
||||
var btcPayWallet = tester.PayTester.GetService<BTCPayWalletProvider>().GetWallet(network);
|
||||
|
@ -633,7 +633,7 @@ namespace BTCPayServer.Tests
|
|||
{
|
||||
await tester.StartAsync();
|
||||
var broadcaster = tester.PayTester.GetService<DelayedTransactionBroadcaster>();
|
||||
var payjoinRepository = tester.PayTester.GetService<PayJoinRepository>();
|
||||
var payjoinRepository = tester.PayTester.GetService<UTXOLocker>();
|
||||
broadcaster.Disable();
|
||||
var network = tester.NetworkProvider.GetNetwork<BTCPayNetwork>("BTC");
|
||||
var btcPayWallet = tester.PayTester.GetService<BTCPayWalletProvider>().GetWallet(network);
|
||||
|
@ -1155,7 +1155,7 @@ retry:
|
|||
Assert.True(invoiceEntity.GetPayments(false).All(p => !p.Accounted));
|
||||
ourOutpoint = invoiceEntity.GetAllBitcoinPaymentData(false).First().PayjoinInformation.ContributedOutPoints[0];
|
||||
});
|
||||
var payjoinRepository = tester.PayTester.GetService<PayJoinRepository>();
|
||||
var payjoinRepository = tester.PayTester.GetService<UTXOLocker>();
|
||||
// The outpoint should now be available for next pj selection
|
||||
Assert.False(await payjoinRepository.TryUnlock(ourOutpoint));
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
private readonly WalletReceiveService _walletReceiveService;
|
||||
private readonly IFeeProviderFactory _feeProviderFactory;
|
||||
private readonly LabelFactory _labelFactory;
|
||||
private readonly UTXOLocker _utxoLocker;
|
||||
|
||||
public GreenfieldStoreOnChainWalletsController(
|
||||
IAuthorizationService authorizationService,
|
||||
|
@ -68,7 +69,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
EventAggregator eventAggregator,
|
||||
WalletReceiveService walletReceiveService,
|
||||
IFeeProviderFactory feeProviderFactory,
|
||||
LabelFactory labelFactory
|
||||
LabelFactory labelFactory,
|
||||
UTXOLocker utxoLocker
|
||||
)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
|
@ -85,6 +87,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
_walletReceiveService = walletReceiveService;
|
||||
_feeProviderFactory = feeProviderFactory;
|
||||
_labelFactory = labelFactory;
|
||||
_utxoLocker = utxoLocker;
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
|
@ -317,9 +320,11 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||
var walletId = new WalletId(storeId, cryptoCode);
|
||||
var walletTransactionsInfoAsync = await _walletRepository.GetWalletTransactionsInfo(walletId);
|
||||
var utxos = await wallet.GetUnspentCoins(derivationScheme.AccountDerivation);
|
||||
|
||||
return Ok(utxos.Select(coin =>
|
||||
{
|
||||
walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info);
|
||||
var labels = info?.Labels ?? new Dictionary<string, LabelData>();
|
||||
return new OnChainWalletUTXOData()
|
||||
{
|
||||
Outpoint = coin.OutPoint,
|
||||
|
|
|
@ -65,11 +65,7 @@ namespace BTCPayServer.Controllers
|
|||
private readonly PayjoinClient _payjoinClient;
|
||||
private readonly LabelFactory _labelFactory;
|
||||
private readonly PullPaymentHostedService _pullPaymentHostedService;
|
||||
private readonly ApplicationDbContextFactory _dbContextFactory;
|
||||
private readonly BTCPayNetworkJsonSerializerSettings _jsonSerializerSettings;
|
||||
private readonly PullPaymentHostedService _pullPaymentService;
|
||||
private readonly IEnumerable<IPayoutHandler> _payoutHandlers;
|
||||
private readonly NBXplorerConnectionFactory _connectionFactory;
|
||||
private readonly UTXOLocker _utxoLocker;
|
||||
private readonly WalletHistogramService _walletHistogramService;
|
||||
|
||||
readonly CurrencyNameTable _currencyTable;
|
||||
|
@ -79,10 +75,8 @@ namespace BTCPayServer.Controllers
|
|||
CurrencyNameTable currencyTable,
|
||||
BTCPayNetworkProvider networkProvider,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
MvcNewtonsoftJsonOptions mvcJsonOptions,
|
||||
NBXplorerDashboard dashboard,
|
||||
WalletHistogramService walletHistogramService,
|
||||
NBXplorerConnectionFactory connectionFactory,
|
||||
RateFetcher rateProvider,
|
||||
IAuthorizationService authorizationService,
|
||||
ExplorerClientProvider explorerProvider,
|
||||
|
@ -94,12 +88,9 @@ namespace BTCPayServer.Controllers
|
|||
DelayedTransactionBroadcaster broadcaster,
|
||||
PayjoinClient payjoinClient,
|
||||
LabelFactory labelFactory,
|
||||
ApplicationDbContextFactory dbContextFactory,
|
||||
BTCPayNetworkJsonSerializerSettings jsonSerializerSettings,
|
||||
PullPaymentHostedService pullPaymentService,
|
||||
IEnumerable<IPayoutHandler> payoutHandlers,
|
||||
IServiceProvider serviceProvider,
|
||||
PullPaymentHostedService pullPaymentHostedService)
|
||||
PullPaymentHostedService pullPaymentHostedService,
|
||||
UTXOLocker utxoLocker)
|
||||
{
|
||||
_currencyTable = currencyTable;
|
||||
Repository = repo;
|
||||
|
@ -119,12 +110,8 @@ namespace BTCPayServer.Controllers
|
|||
_payjoinClient = payjoinClient;
|
||||
_labelFactory = labelFactory;
|
||||
_pullPaymentHostedService = pullPaymentHostedService;
|
||||
_dbContextFactory = dbContextFactory;
|
||||
_jsonSerializerSettings = jsonSerializerSettings;
|
||||
_pullPaymentService = pullPaymentService;
|
||||
_payoutHandlers = payoutHandlers;
|
||||
_utxoLocker = utxoLocker;
|
||||
ServiceProvider = serviceProvider;
|
||||
_connectionFactory = connectionFactory;
|
||||
_walletHistogramService = walletHistogramService;
|
||||
}
|
||||
|
||||
|
@ -625,15 +612,15 @@ namespace BTCPayServer.Controllers
|
|||
vm.InputsAvailable = utxos.Select(coin =>
|
||||
{
|
||||
walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info);
|
||||
var labels = info?.Labels == null
|
||||
? new List<ColoredLabel>()
|
||||
: _labelFactory.ColorizeTransactionLabels(walletBlobAsync, info, Request).ToList();
|
||||
return new WalletSendModel.InputSelectionOption()
|
||||
{
|
||||
Outpoint = coin.OutPoint.ToString(),
|
||||
Amount = coin.Value.GetValue(network),
|
||||
Comment = info?.Comment,
|
||||
Labels =
|
||||
info == null
|
||||
? null
|
||||
: _labelFactory.ColorizeTransactionLabels(walletBlobAsync, info, Request),
|
||||
Labels = labels,
|
||||
Link = string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink,
|
||||
coin.OutPoint.Hash.ToString()),
|
||||
Confirmations = coin.Confirmations
|
||||
|
|
|
@ -14,8 +14,6 @@ using BTCPayServer.Services.Apps;
|
|||
using BTCPayServer.Services.Labels;
|
||||
using BTCPayServer.Services.PaymentRequests;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.HostedServices
|
||||
{
|
||||
|
@ -48,14 +46,6 @@ namespace BTCPayServer.HostedServices
|
|||
{
|
||||
UpdateTransactionLabel.InvoiceLabelTemplate(invoiceEvent.Invoice.Id)
|
||||
};
|
||||
|
||||
if (invoiceEvent.Invoice.GetPayments(invoiceEvent.Payment.GetCryptoCode(), false).Any(entity =>
|
||||
entity.GetCryptoPaymentData() is BitcoinLikePaymentData pData &&
|
||||
pData.PayjoinInformation?.CoinjoinTransactionHash == transactionId))
|
||||
{
|
||||
labels.Add(UpdateTransactionLabel.PayjoinLabelTemplate());
|
||||
}
|
||||
|
||||
foreach (var paymentId in PaymentRequestRepository.GetPaymentIdsFromInternalTags(invoiceEvent.Invoice))
|
||||
{
|
||||
labels.Add(UpdateTransactionLabel.PaymentRequestLabelTemplate(paymentId));
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||
public class NBXplorerListener : IHostedService
|
||||
{
|
||||
readonly EventAggregator _Aggregator;
|
||||
private readonly PayJoinRepository _payJoinRepository;
|
||||
private readonly UTXOLocker _utxoLocker;
|
||||
readonly ExplorerClientProvider _ExplorerClients;
|
||||
private readonly PaymentService _paymentService;
|
||||
readonly InvoiceRepository _InvoiceRepository;
|
||||
|
@ -38,7 +38,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||
BTCPayWalletProvider wallets,
|
||||
InvoiceRepository invoiceRepository,
|
||||
EventAggregator aggregator,
|
||||
PayJoinRepository payjoinRepository,
|
||||
UTXOLocker payjoinRepository,
|
||||
PaymentService paymentService,
|
||||
Logs logs)
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||
_InvoiceRepository = invoiceRepository;
|
||||
_ExplorerClients = explorerClients;
|
||||
_Aggregator = aggregator;
|
||||
_payJoinRepository = payjoinRepository;
|
||||
_utxoLocker = payjoinRepository;
|
||||
_paymentService = paymentService;
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||
// reuse our outpoint for another PJ
|
||||
(originalPJBroadcastable is false && !cjPJBroadcasted))
|
||||
{
|
||||
await _payJoinRepository.TryUnlock(payjoinInformation.ContributedOutPoints);
|
||||
await _utxoLocker.TryUnlock(payjoinInformation.ContributedOutPoints);
|
||||
}
|
||||
|
||||
await _paymentService.UpdatePayments(updatedPaymentEntities);
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
private readonly InvoiceRepository _invoiceRepository;
|
||||
private readonly ExplorerClientProvider _explorerClientProvider;
|
||||
private readonly BTCPayWalletProvider _btcPayWalletProvider;
|
||||
private readonly PayJoinRepository _payJoinRepository;
|
||||
private readonly UTXOLocker _utxoLocker;
|
||||
private readonly EventAggregator _eventAggregator;
|
||||
private readonly NBXplorerDashboard _dashboard;
|
||||
private readonly DelayedTransactionBroadcaster _broadcaster;
|
||||
|
@ -97,7 +97,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
public PayJoinEndpointController(BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
InvoiceRepository invoiceRepository, ExplorerClientProvider explorerClientProvider,
|
||||
BTCPayWalletProvider btcPayWalletProvider,
|
||||
PayJoinRepository payJoinRepository,
|
||||
UTXOLocker utxoLocker,
|
||||
EventAggregator eventAggregator,
|
||||
NBXplorerDashboard dashboard,
|
||||
DelayedTransactionBroadcaster broadcaster,
|
||||
|
@ -111,7 +111,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
_invoiceRepository = invoiceRepository;
|
||||
_explorerClientProvider = explorerClientProvider;
|
||||
_btcPayWalletProvider = btcPayWalletProvider;
|
||||
_payJoinRepository = payJoinRepository;
|
||||
_utxoLocker = utxoLocker;
|
||||
_eventAggregator = eventAggregator;
|
||||
_dashboard = dashboard;
|
||||
_broadcaster = broadcaster;
|
||||
|
@ -148,7 +148,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
});
|
||||
}
|
||||
|
||||
await using var ctx = new PayjoinReceiverContext(_invoiceRepository, _explorerClientProvider.GetExplorerClient(network), _payJoinRepository, Logs);
|
||||
await using var ctx = new PayjoinReceiverContext(_invoiceRepository, _explorerClientProvider.GetExplorerClient(network), _utxoLocker, Logs);
|
||||
ObjectResult CreatePayjoinErrorAndLog(int httpCode, PayjoinReceiverWellknownErrors err, string debug)
|
||||
{
|
||||
ctx.Logs.Write($"Payjoin error: {debug}", InvoiceEventData.EventSeverity.Error);
|
||||
|
@ -322,7 +322,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
}
|
||||
|
||||
|
||||
if (!await _payJoinRepository.TryLockInputs(ctx.OriginalTransaction.Inputs.Select(i => i.PrevOut).ToArray()))
|
||||
if (!await _utxoLocker.TryLockInputs(ctx.OriginalTransaction.Inputs.Select(i => i.PrevOut).ToArray()))
|
||||
{
|
||||
// We do not broadcast, since we might double spend a delayed transaction of a previous payjoin
|
||||
ctx.DoNotBroadcast();
|
||||
|
@ -502,18 +502,23 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
_eventAggregator.Publish(new InvoiceEvent(invoice, InvoiceEvent.ReceivedPayment) { Payment = payment });
|
||||
}
|
||||
|
||||
|
||||
await _btcPayWalletProvider.GetWallet(network).SaveOffchainTransactionAsync(ctx.OriginalTransaction);
|
||||
var labels = selectedUTXOs.GroupBy(pair => pair.Key.Hash).Select(utxo =>
|
||||
new KeyValuePair<uint256, List<(string color, Label label)>>(utxo.Key,
|
||||
new List<(string color, Label label)>()
|
||||
{
|
||||
UpdateTransactionLabel.PayjoinExposedLabelTemplate(invoice?.Id)
|
||||
}))
|
||||
.ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
|
||||
labels.Add(originalPaymentData.PayjoinInformation.CoinjoinTransactionHash, new List<(string color, Label label)>()
|
||||
{
|
||||
UpdateTransactionLabel.PayjoinLabelTemplate()
|
||||
});
|
||||
_eventAggregator.Publish(new UpdateTransactionLabel()
|
||||
{
|
||||
WalletId = walletId,
|
||||
TransactionLabels = selectedUTXOs.GroupBy(pair => pair.Key.Hash).Select(utxo =>
|
||||
new KeyValuePair<uint256, List<(string color, Label label)>>(utxo.Key,
|
||||
new List<(string color, Label label)>()
|
||||
{
|
||||
UpdateTransactionLabel.PayjoinExposedLabelTemplate(invoice?.Id)
|
||||
}))
|
||||
.ToDictionary(pair => pair.Key, pair => pair.Value)
|
||||
TransactionLabels = labels
|
||||
});
|
||||
ctx.Success();
|
||||
// BTCPay Server support PSBT set as hex
|
||||
|
@ -608,7 +613,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
{
|
||||
continue;
|
||||
}
|
||||
if (await _payJoinRepository.TryLock(availableUtxo.Outpoint))
|
||||
if (await _utxoLocker.TryLock(availableUtxo.Outpoint))
|
||||
{
|
||||
return (new[] { availableUtxo }, PayjoinUtxoSelectionType.HeuristicBased);
|
||||
}
|
||||
|
@ -620,7 +625,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
{
|
||||
if (currentTry >= maxTries)
|
||||
break;
|
||||
if (await _payJoinRepository.TryLock(utxo.Outpoint))
|
||||
if (await _utxoLocker.TryLock(utxo.Outpoint))
|
||||
{
|
||||
return (new[] { utxo }, PayjoinUtxoSelectionType.Ordered);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
{
|
||||
services.AddSingleton<DelayedTransactionBroadcaster>();
|
||||
services.AddSingleton<IHostedService, HostedServices.DelayedTransactionBroadcasterHostedService>();
|
||||
services.AddSingleton<PayJoinRepository>();
|
||||
services.AddSingleton<UTXOLocker>();
|
||||
services.AddSingleton<IUTXOLocker>(provider => provider.GetRequiredService<UTXOLocker>());
|
||||
services.AddSingleton<IPayjoinServerCommunicator, PayjoinServerCommunicator>();
|
||||
services.AddSingleton<PayjoinClient>();
|
||||
services.AddTransient<Socks5HttpClientHandler>();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -6,21 +7,19 @@ using NBitcoin;
|
|||
|
||||
namespace BTCPayServer.Payments.PayJoin
|
||||
{
|
||||
public class PayJoinRepository
|
||||
public class UTXOLocker : IUTXOLocker
|
||||
{
|
||||
private readonly ApplicationDbContextFactory _dbContextFactory;
|
||||
|
||||
public PayJoinRepository(ApplicationDbContextFactory dbContextFactory)
|
||||
public UTXOLocker(ApplicationDbContextFactory dbContextFactory)
|
||||
{
|
||||
_dbContextFactory = dbContextFactory;
|
||||
}
|
||||
|
||||
public async Task<bool> TryLock(OutPoint outpoint)
|
||||
{
|
||||
using var ctx = _dbContextFactory.CreateContext();
|
||||
ctx.PayjoinLocks.Add(new PayjoinLock()
|
||||
{
|
||||
Id = outpoint.ToString()
|
||||
});
|
||||
ctx.PayjoinLocks.Add(new PayjoinLock() {Id = outpoint.ToString()});
|
||||
try
|
||||
{
|
||||
return await ctx.SaveChangesAsync() == 1;
|
||||
|
@ -36,11 +35,9 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
using var ctx = _dbContextFactory.CreateContext();
|
||||
foreach (OutPoint outPoint in outPoints)
|
||||
{
|
||||
ctx.PayjoinLocks.Remove(new PayjoinLock()
|
||||
{
|
||||
Id = outPoint.ToString()
|
||||
});
|
||||
ctx.PayjoinLocks.Remove(new PayjoinLock() {Id = outPoint.ToString()});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await ctx.SaveChangesAsync() == outPoints.Length;
|
||||
|
@ -63,6 +60,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
Id = "K-" + outPoint.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await ctx.SaveChangesAsync() == outPoints.Length;
|
||||
|
@ -72,5 +70,13 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<HashSet<OutPoint>> FindLocks(OutPoint[] outpoints)
|
||||
{
|
||||
var outPointsStr = outpoints.Select(o => o.ToString());
|
||||
await using var ctx = _dbContextFactory.CreateContext();
|
||||
return (await ctx.PayjoinLocks.Where(l => outPointsStr.Contains(l.Id)).ToArrayAsync())
|
||||
.Select(l => OutPoint.Parse(l.Id)).ToHashSet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
{
|
||||
private readonly InvoiceRepository _invoiceRepository;
|
||||
private readonly ExplorerClient _explorerClient;
|
||||
private readonly PayJoinRepository _payJoinRepository;
|
||||
private readonly UTXOLocker _utxoLocker;
|
||||
private readonly BTCPayServer.Logging.Logs BTCPayLogs;
|
||||
public PayjoinReceiverContext(InvoiceRepository invoiceRepository, ExplorerClient explorerClient, PayJoinRepository payJoinRepository, BTCPayServer.Logging.Logs logs)
|
||||
public PayjoinReceiverContext(InvoiceRepository invoiceRepository, ExplorerClient explorerClient, UTXOLocker utxoLocker, BTCPayServer.Logging.Logs logs)
|
||||
{
|
||||
this.BTCPayLogs = logs;
|
||||
_invoiceRepository = invoiceRepository;
|
||||
_explorerClient = explorerClient;
|
||||
_payJoinRepository = payJoinRepository;
|
||||
_utxoLocker = utxoLocker;
|
||||
}
|
||||
public Invoice Invoice { get; set; }
|
||||
public NBitcoin.Transaction OriginalTransaction { get; set; }
|
||||
|
@ -40,7 +40,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||
}
|
||||
if (!success && LockedUTXOs != null)
|
||||
{
|
||||
disposing.Add(_payJoinRepository.TryUnlock(LockedUTXOs));
|
||||
disposing.Add(_utxoLocker.TryUnlock(LockedUTXOs));
|
||||
}
|
||||
try
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace BTCPayServer.Services.Labels
|
|||
{
|
||||
Text = uncoloredLabel.Text,
|
||||
Color = color,
|
||||
Tooltip = "",
|
||||
TextColor = TextColor(color)
|
||||
};
|
||||
|
||||
|
@ -108,7 +109,10 @@ namespace BTCPayServer.Services.Labels
|
|||
? null
|
||||
: _linkGenerator.PayoutLink(payoutLabel.WalletId, null, PayoutState.Completed, request.Scheme, request.Host,
|
||||
request.PathBase);
|
||||
|
||||
}
|
||||
else if (uncoloredLabel.Text == "payjoin")
|
||||
{
|
||||
coloredLabel.Tooltip = $"This UTXO was part of a PayJoin transaction.";
|
||||
}
|
||||
return coloredLabel;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue