mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 18:11:36 +01:00
b31fb1a269
* Auto label utxos based on invoice and payjoin This PR introduces automatic labelling to transactions. * If it is an incoming tx to an invoice, it will tag it as such. * If it was a payjoin tx , it will tag it as such. * If a transaction's inputs were exposed to a payjoin sender, we tag it as such. * wip * wip * support in coinselection * remove ugly hack * support wallet transactions page * remove messy loop * better label template helpers * add tests and susbcribe to event * simplify data * fix test * fix label + color * fix remove label * renove useless call * add toString * fix potential crash by txid * trim json keyword in manual label * format file
129 lines
5.2 KiB
C#
129 lines
5.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BTCPayServer.Data;
|
|
using BTCPayServer.Events;
|
|
using BTCPayServer.Payments;
|
|
using BTCPayServer.Payments.Bitcoin;
|
|
using BTCPayServer.Services;
|
|
using NBitcoin;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace BTCPayServer.HostedServices
|
|
{
|
|
public class TransactionLabelMarkerHostedService : EventHostedServiceBase
|
|
{
|
|
private readonly EventAggregator _eventAggregator;
|
|
private readonly WalletRepository _walletRepository;
|
|
|
|
public TransactionLabelMarkerHostedService(EventAggregator eventAggregator, WalletRepository walletRepository) :
|
|
base(eventAggregator)
|
|
{
|
|
_eventAggregator = eventAggregator;
|
|
_walletRepository = walletRepository;
|
|
}
|
|
|
|
protected override void SubscribeToEvents()
|
|
{
|
|
Subscribe<InvoiceEvent>();
|
|
Subscribe<UpdateTransactionLabel>();
|
|
}
|
|
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
|
|
{
|
|
if (evt is InvoiceEvent invoiceEvent && invoiceEvent.Name == InvoiceEvent.ReceivedPayment &&
|
|
invoiceEvent.Payment.GetPaymentMethodId().PaymentType == BitcoinPaymentType.Instance &&
|
|
invoiceEvent.Payment.GetCryptoPaymentData() is BitcoinLikePaymentData bitcoinLikePaymentData)
|
|
{
|
|
var walletId = new WalletId(invoiceEvent.Invoice.StoreId, invoiceEvent.Payment.GetCryptoCode());
|
|
var transactionId = bitcoinLikePaymentData.Outpoint.Hash;
|
|
var labels = new List<(string color, string label)>
|
|
{
|
|
UpdateTransactionLabel.InvoiceLabelTemplate(invoiceEvent.Invoice.Id)
|
|
};
|
|
|
|
if (invoiceEvent.Invoice.GetPayments(invoiceEvent.Payment.GetCryptoCode()).Any(entity =>
|
|
entity.GetCryptoPaymentData() is BitcoinLikePaymentData pData &&
|
|
pData.PayjoinInformation?.CoinjoinTransactionHash == transactionId))
|
|
{
|
|
labels.Add(UpdateTransactionLabel.PayjoinLabelTemplate());
|
|
}
|
|
|
|
_eventAggregator.Publish(new UpdateTransactionLabel()
|
|
{
|
|
WalletId = walletId,
|
|
TransactionLabels =
|
|
new Dictionary<uint256, List<(string color, string label)>>() {{transactionId, labels}}
|
|
});
|
|
}
|
|
else if (evt is UpdateTransactionLabel updateTransactionLabel)
|
|
{
|
|
var walletTransactionsInfo =
|
|
await _walletRepository.GetWalletTransactionsInfo(updateTransactionLabel.WalletId);
|
|
var walletBlobInfo = await _walletRepository.GetWalletInfo(updateTransactionLabel.WalletId);
|
|
await Task.WhenAll(updateTransactionLabel.TransactionLabels.Select(async pair =>
|
|
{
|
|
if (!walletTransactionsInfo.TryGetValue(pair.Key.ToString(), out var walletTransactionInfo))
|
|
{
|
|
walletTransactionInfo = new WalletTransactionInfo();
|
|
}
|
|
|
|
foreach (var label in pair.Value)
|
|
{
|
|
walletBlobInfo.LabelColors.TryAdd(label.label, label.color);
|
|
}
|
|
|
|
await _walletRepository.SetWalletInfo(updateTransactionLabel.WalletId, walletBlobInfo);
|
|
var update = false;
|
|
foreach (var label in pair.Value)
|
|
{
|
|
if (walletTransactionInfo.Labels.Add(label.label))
|
|
{
|
|
update = true;
|
|
}
|
|
}
|
|
|
|
if (update)
|
|
{
|
|
await _walletRepository.SetWalletTransactionInfo(updateTransactionLabel.WalletId,
|
|
pair.Key.ToString(), walletTransactionInfo);
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
public class UpdateTransactionLabel
|
|
{
|
|
public static (string color, string label) PayjoinLabelTemplate()
|
|
{
|
|
return ("#51b13e", "payjoin");
|
|
}
|
|
|
|
public static (string color, string label) InvoiceLabelTemplate(string invoice)
|
|
{
|
|
return ("#cedc21", JObject.FromObject(new {value = "invoice", id = invoice}).ToString());
|
|
}
|
|
|
|
public static (string color, string label) PayjoinExposedLabelTemplate(string invoice)
|
|
{
|
|
return ("#51b13e", JObject.FromObject(new {value = "pj-exposed", id = invoice}).ToString());
|
|
}
|
|
|
|
public WalletId WalletId { get; set; }
|
|
public Dictionary<uint256, List<(string color, string label)>> TransactionLabels { get; set; }
|
|
public override string ToString()
|
|
{
|
|
var result = new StringBuilder();
|
|
foreach (var transactionLabel in TransactionLabels)
|
|
{
|
|
result.AppendLine(
|
|
$"Adding {transactionLabel.Value.Count} labels to {transactionLabel.Key} in wallet {WalletId}");
|
|
}
|
|
|
|
return result.ToString();
|
|
}
|
|
}
|
|
}
|