mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 01:43:50 +01:00
Fix monero payments
This commit is contained in:
parent
d7fd90c4c3
commit
b7affb1d34
@ -727,5 +727,39 @@
|
|||||||
},
|
},
|
||||||
"version": 2
|
"version": 2
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "payment",
|
||||||
|
"input": {
|
||||||
|
"output": null,
|
||||||
|
"version": 1,
|
||||||
|
"outpoint": null,
|
||||||
|
"accounted": true,
|
||||||
|
"cryptoCode": "XMR",
|
||||||
|
"networkFee": 0.0000000019,
|
||||||
|
"receivedTimeMs": 1705500405468,
|
||||||
|
"cryptoPaymentData": "{\"Amount\":62700000000,\"Address\":\"85CjjvQyW7PjNmiFRKZuEHKzZjiB3rjSu6n8zPzji4PtQxw1CyEY5H5FBge6GRUMJqR7FqsgBHU7H1FpEppvZXS6HGpFF6t\",\"SubaddressIndex\":23,\"SubaccountIndex\":0,\"BlockHeight\":3063946,\"ConfirmationCount\":10,\"TransactionId\":\"cc2e9ef03864c6af5e0d6f1c730ba142144f6588c50035b2996a59a6f3771b06\",\"LockTime\":0}",
|
||||||
|
"cryptoPaymentDataType": "MoneroLike"
|
||||||
|
},
|
||||||
|
"expected": {
|
||||||
|
"divisibility": 12,
|
||||||
|
"destination": "85CjjvQyW7PjNmiFRKZuEHKzZjiB3rjSu6n8zPzji4PtQxw1CyEY5H5FBge6GRUMJqR7FqsgBHU7H1FpEppvZXS6HGpFF6t",
|
||||||
|
"details": {
|
||||||
|
"blockHeight": 3063946,
|
||||||
|
"confirmationCount": 10,
|
||||||
|
"lockTime": 0,
|
||||||
|
"subaccountIndex": 0,
|
||||||
|
"subaddressIndex": 23,
|
||||||
|
"transactionId": "cc2e9ef03864c6af5e0d6f1c730ba142144f6588c50035b2996a59a6f3771b06"
|
||||||
|
},
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"expectedProperties": {
|
||||||
|
"Amount": "0.0627",
|
||||||
|
"PaymentMethodId": "XMR-CHAIN",
|
||||||
|
"Currency": "XMR",
|
||||||
|
"Status": "Settled",
|
||||||
|
"Accounted": null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -430,7 +430,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
bip21 = new BitcoinUrlBuilder(destination.Destination, network.NBitcoinNetwork);
|
bip21 = new BitcoinUrlBuilder(destination.Destination, network.NBitcoinNetwork);
|
||||||
amount ??= bip21.Amount.GetValue(network);
|
amount ??= bip21.Amount?.GetValue(network);
|
||||||
if (bip21.Address is null)
|
if (bip21.Address is null)
|
||||||
request.AddModelError(transactionRequest => transactionRequest.Destinations[index],
|
request.AddModelError(transactionRequest => transactionRequest.Destinations[index],
|
||||||
"This BIP21 destination is missing a bitcoin address", this);
|
"This BIP21 destination is missing a bitcoin address", this);
|
||||||
|
@ -3,10 +3,12 @@ using System.Collections.Concurrent;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Client.Models;
|
using BTCPayServer.Client.Models;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Events;
|
using BTCPayServer.Events;
|
||||||
|
using BTCPayServer.HostedServices;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Plugins.Altcoins;
|
using BTCPayServer.Plugins.Altcoins;
|
||||||
using BTCPayServer.Services.Altcoins.Monero.Configuration;
|
using BTCPayServer.Services.Altcoins.Monero.Configuration;
|
||||||
@ -24,7 +26,7 @@ using Newtonsoft.Json.Linq;
|
|||||||
|
|
||||||
namespace BTCPayServer.Services.Altcoins.Monero.Services
|
namespace BTCPayServer.Services.Altcoins.Monero.Services
|
||||||
{
|
{
|
||||||
public class MoneroListener : IHostedService
|
public class MoneroListener : EventHostedServiceBase
|
||||||
{
|
{
|
||||||
private readonly InvoiceRepository _invoiceRepository;
|
private readonly InvoiceRepository _invoiceRepository;
|
||||||
private readonly EventAggregator _eventAggregator;
|
private readonly EventAggregator _eventAggregator;
|
||||||
@ -35,9 +37,6 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||||
private readonly InvoiceActivator _invoiceActivator;
|
private readonly InvoiceActivator _invoiceActivator;
|
||||||
private readonly PaymentService _paymentService;
|
private readonly PaymentService _paymentService;
|
||||||
private readonly CompositeDisposable leases = new CompositeDisposable();
|
|
||||||
private readonly Queue<Func<CancellationToken, Task>> taskQueue = new Queue<Func<CancellationToken, Task>>();
|
|
||||||
private CancellationTokenSource _Cts;
|
|
||||||
|
|
||||||
public MoneroListener(InvoiceRepository invoiceRepository,
|
public MoneroListener(InvoiceRepository invoiceRepository,
|
||||||
EventAggregator eventAggregator,
|
EventAggregator eventAggregator,
|
||||||
@ -47,7 +46,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
ILogger<MoneroListener> logger,
|
ILogger<MoneroListener> logger,
|
||||||
PaymentMethodHandlerDictionary handlers,
|
PaymentMethodHandlerDictionary handlers,
|
||||||
InvoiceActivator invoiceActivator,
|
InvoiceActivator invoiceActivator,
|
||||||
PaymentService paymentService)
|
PaymentService paymentService) : base(eventAggregator, logger)
|
||||||
{
|
{
|
||||||
_invoiceRepository = invoiceRepository;
|
_invoiceRepository = invoiceRepository;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
@ -60,73 +59,43 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
_paymentService = paymentService;
|
_paymentService = paymentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
protected override void SubscribeToEvents()
|
||||||
{
|
{
|
||||||
if (!_MoneroLikeConfiguration.MoneroLikeConfigurationItems.Any())
|
base.SubscribeToEvents();
|
||||||
{
|
Subscribe<MoneroEvent>();
|
||||||
return Task.CompletedTask;
|
Subscribe<MoneroRPCProvider.MoneroDaemonStateChange>();
|
||||||
}
|
}
|
||||||
_Cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
|
||||||
|
|
||||||
leases.Add(_eventAggregator.Subscribe<MoneroEvent>(OnMoneroEvent));
|
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
|
||||||
leases.Add(_eventAggregator.Subscribe<MoneroRPCProvider.MoneroDaemonStateChange>(e =>
|
{
|
||||||
|
if (evt is MoneroRPCProvider.MoneroDaemonStateChange stateChange)
|
||||||
{
|
{
|
||||||
if (_moneroRpcProvider.IsAvailable(e.CryptoCode))
|
if (_moneroRpcProvider.IsAvailable(stateChange.CryptoCode))
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"{e.CryptoCode} just became available");
|
_logger.LogInformation($"{stateChange.CryptoCode} just became available");
|
||||||
_ = UpdateAnyPendingMoneroLikePayment(e.CryptoCode);
|
_ = UpdateAnyPendingMoneroLikePayment(stateChange.CryptoCode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"{e.CryptoCode} just became unavailable");
|
_logger.LogInformation($"{stateChange.CryptoCode} just became unavailable");
|
||||||
}
|
}
|
||||||
}));
|
}
|
||||||
_ = WorkThroughQueue(_Cts.Token);
|
else if (evt is MoneroEvent moneroEvent)
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task WorkThroughQueue(CancellationToken token)
|
|
||||||
{
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
if (taskQueue.TryDequeue(out var t))
|
if (!_moneroRpcProvider.IsAvailable(moneroEvent.CryptoCode))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(moneroEvent.BlockHash))
|
||||||
{
|
{
|
||||||
try
|
await OnNewBlock(moneroEvent.CryptoCode);
|
||||||
{
|
|
||||||
|
|
||||||
await t.Invoke(token);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
|
|
||||||
_logger.LogError($"error with queue item", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
if (!string.IsNullOrEmpty(moneroEvent.TransactionHash))
|
||||||
{
|
{
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1), token);
|
await OnTransactionUpdated(moneroEvent.CryptoCode, moneroEvent.TransactionHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMoneroEvent(MoneroEvent obj)
|
|
||||||
{
|
|
||||||
if (!_moneroRpcProvider.IsAvailable(obj.CryptoCode))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(obj.BlockHash))
|
|
||||||
{
|
|
||||||
taskQueue.Enqueue(token => OnNewBlock(obj.CryptoCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(obj.TransactionHash))
|
|
||||||
{
|
|
||||||
taskQueue.Enqueue(token => OnTransactionUpdated(obj.CryptoCode, obj.TransactionHash));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ReceivedPayment(InvoiceEntity invoice, PaymentEntity payment)
|
private async Task ReceivedPayment(InvoiceEntity invoice, PaymentEntity payment)
|
||||||
{
|
{
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
@ -204,7 +173,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
|
|
||||||
var transferProcessingTasks = new List<Task>();
|
var transferProcessingTasks = new List<Task>();
|
||||||
|
|
||||||
var updatedPaymentEntities = new BlockingCollection<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
var updatedPaymentEntities = new List<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
||||||
foreach (var keyValuePair in tasks)
|
foreach (var keyValuePair in tasks)
|
||||||
{
|
{
|
||||||
var transfers = keyValuePair.Value.Result.In;
|
var transfers = keyValuePair.Value.Result.In;
|
||||||
@ -256,14 +225,6 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
leases.Dispose();
|
|
||||||
_Cts?.Cancel();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnNewBlock(string cryptoCode)
|
private async Task OnNewBlock(string cryptoCode)
|
||||||
{
|
{
|
||||||
await UpdateAnyPendingMoneroLikePayment(cryptoCode);
|
await UpdateAnyPendingMoneroLikePayment(cryptoCode);
|
||||||
@ -278,7 +239,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
"get_transfer_by_txid",
|
"get_transfer_by_txid",
|
||||||
new GetTransferByTransactionIdRequest() { TransactionId = transactionHash });
|
new GetTransferByTransactionIdRequest() { TransactionId = transactionHash });
|
||||||
|
|
||||||
var paymentsToUpdate = new BlockingCollection<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
var paymentsToUpdate = new List<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
||||||
|
|
||||||
//group all destinations of the tx together and loop through the sets
|
//group all destinations of the tx together and loop through the sets
|
||||||
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
||||||
@ -317,7 +278,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
private async Task HandlePaymentData(string cryptoCode, string address, long totalAmount, long subaccountIndex,
|
private async Task HandlePaymentData(string cryptoCode, string address, long totalAmount, long subaccountIndex,
|
||||||
long subaddressIndex,
|
long subaddressIndex,
|
||||||
string txId, long confirmations, long blockHeight, long locktime, InvoiceEntity invoice,
|
string txId, long confirmations, long blockHeight, long locktime, InvoiceEntity invoice,
|
||||||
BlockingCollection<(PaymentEntity Payment, InvoiceEntity invoice)> paymentsToUpdate)
|
List<(PaymentEntity Payment, InvoiceEntity invoice)> paymentsToUpdate)
|
||||||
{
|
{
|
||||||
var network = _networkProvider.GetNetwork(cryptoCode);
|
var network = _networkProvider.GetNetwork(cryptoCode);
|
||||||
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(network.CryptoCode);
|
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(network.CryptoCode);
|
||||||
@ -333,9 +294,10 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
LockTime = locktime,
|
LockTime = locktime,
|
||||||
InvoiceSettledConfirmationThreshold = promptDetails.InvoiceSettledConfirmationThreshold
|
InvoiceSettledConfirmationThreshold = promptDetails.InvoiceSettledConfirmationThreshold
|
||||||
};
|
};
|
||||||
|
var status = GetStatus(details, invoice.SpeedPolicy) ? PaymentStatus.Settled : PaymentStatus.Processing;
|
||||||
var paymentData = new Data.PaymentData()
|
var paymentData = new Data.PaymentData()
|
||||||
{
|
{
|
||||||
Status = GetStatus(details, invoice.SpeedPolicy) ? PaymentStatus.Settled : PaymentStatus.Processing,
|
Status = status,
|
||||||
Amount = MoneroMoney.Convert(totalAmount),
|
Amount = MoneroMoney.Convert(totalAmount),
|
||||||
Created = DateTimeOffset.UtcNow,
|
Created = DateTimeOffset.UtcNow,
|
||||||
Id = $"{txId}#{subaccountIndex}#{subaddressIndex}",
|
Id = $"{txId}#{subaccountIndex}#{subaddressIndex}",
|
||||||
@ -346,11 +308,10 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
|
|
||||||
//check if this tx exists as a payment to this invoice already
|
//check if this tx exists as a payment to this invoice already
|
||||||
var alreadyExistingPaymentThatMatches = GetAllMoneroLikePayments(invoice, cryptoCode)
|
var alreadyExistingPaymentThatMatches = GetAllMoneroLikePayments(invoice, cryptoCode)
|
||||||
.Select(entity => (Payment: entity, PaymentData: handler.ParsePaymentDetails(entity.Details)))
|
.SingleOrDefault(c => c.Id == paymentData.Id && c.PaymentMethodId == pmi);
|
||||||
.SingleOrDefault(c => c.Payment.PaymentMethodId == pmi);
|
|
||||||
|
|
||||||
//if it doesnt, add it and assign a new monerolike address to the system if a balance is still due
|
//if it doesnt, add it and assign a new monerolike address to the system if a balance is still due
|
||||||
if (alreadyExistingPaymentThatMatches.Payment == null)
|
if (alreadyExistingPaymentThatMatches == null)
|
||||||
{
|
{
|
||||||
var payment = await _paymentService.AddPayment(paymentData, [txId]);
|
var payment = await _paymentService.AddPayment(paymentData, [txId]);
|
||||||
if (payment != null)
|
if (payment != null)
|
||||||
@ -359,9 +320,9 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//else update it with the new data
|
//else update it with the new data
|
||||||
alreadyExistingPaymentThatMatches.PaymentData = details;
|
alreadyExistingPaymentThatMatches.Status = status;
|
||||||
alreadyExistingPaymentThatMatches.Payment.Details = JToken.FromObject(paymentData, handler.Serializer);
|
alreadyExistingPaymentThatMatches.Details = JToken.FromObject(details, handler.Serializer);
|
||||||
paymentsToUpdate.Add((alreadyExistingPaymentThatMatches.Payment, invoice));
|
paymentsToUpdate.Add((alreadyExistingPaymentThatMatches, invoice));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||||||
using BTCPayServer.Client.Models;
|
using BTCPayServer.Client.Models;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Events;
|
using BTCPayServer.Events;
|
||||||
|
using BTCPayServer.HostedServices;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Plugins.Altcoins;
|
using BTCPayServer.Plugins.Altcoins;
|
||||||
using BTCPayServer.Services.Altcoins.Zcash.Configuration;
|
using BTCPayServer.Services.Altcoins.Zcash.Configuration;
|
||||||
@ -26,7 +27,7 @@ using static BTCPayServer.Client.Models.InvoicePaymentMethodDataModel;
|
|||||||
|
|
||||||
namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
||||||
{
|
{
|
||||||
public class ZcashListener : IHostedService
|
public class ZcashListener : EventHostedServiceBase
|
||||||
{
|
{
|
||||||
private readonly InvoiceRepository _invoiceRepository;
|
private readonly InvoiceRepository _invoiceRepository;
|
||||||
private readonly EventAggregator _eventAggregator;
|
private readonly EventAggregator _eventAggregator;
|
||||||
@ -37,19 +38,16 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
private readonly PaymentService _paymentService;
|
private readonly PaymentService _paymentService;
|
||||||
private readonly InvoiceActivator _invoiceActivator;
|
private readonly InvoiceActivator _invoiceActivator;
|
||||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||||
private readonly CompositeDisposable leases = new CompositeDisposable();
|
|
||||||
private readonly Channel<Func<Task>> _requests = Channel.CreateUnbounded<Func<Task>>();
|
|
||||||
private CancellationTokenSource _Cts;
|
|
||||||
|
|
||||||
public ZcashListener(InvoiceRepository invoiceRepository,
|
public ZcashListener(InvoiceRepository invoiceRepository,
|
||||||
EventAggregator eventAggregator,
|
EventAggregator eventAggregator,
|
||||||
ZcashRPCProvider ZcashRpcProvider,
|
ZcashRPCProvider ZcashRpcProvider,
|
||||||
ZcashLikeConfiguration ZcashLikeConfiguration,
|
ZcashLikeConfiguration ZcashLikeConfiguration,
|
||||||
BTCPayNetworkProvider networkProvider,
|
BTCPayNetworkProvider networkProvider,
|
||||||
ILogger<ZcashListener> logger,
|
ILogger<ZcashListener> logger,
|
||||||
PaymentService paymentService,
|
PaymentService paymentService,
|
||||||
InvoiceActivator invoiceActivator,
|
InvoiceActivator invoiceActivator,
|
||||||
PaymentMethodHandlerDictionary handlers)
|
PaymentMethodHandlerDictionary handlers) : base(eventAggregator, logger)
|
||||||
{
|
{
|
||||||
_invoiceRepository = invoiceRepository;
|
_invoiceRepository = invoiceRepository;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
@ -62,63 +60,39 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
_handlers = handlers;
|
_handlers = handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
protected override void SubscribeToEvents()
|
||||||
{
|
{
|
||||||
if (!_ZcashLikeConfiguration.ZcashLikeConfigurationItems.Any())
|
base.SubscribeToEvents();
|
||||||
{
|
Subscribe<ZcashEvent>();
|
||||||
return Task.CompletedTask;
|
Subscribe<ZcashRPCProvider.ZcashDaemonStateChange>();
|
||||||
}
|
}
|
||||||
_Cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
|
||||||
|
|
||||||
leases.Add(_eventAggregator.Subscribe<ZcashEvent>(OnZcashEvent));
|
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
|
||||||
leases.Add(_eventAggregator.Subscribe<ZcashRPCProvider.ZcashDaemonStateChange>(e =>
|
{
|
||||||
|
if (evt is ZcashRPCProvider.ZcashDaemonStateChange stateChanged)
|
||||||
{
|
{
|
||||||
if (_ZcashRpcProvider.IsAvailable(e.CryptoCode))
|
if (_ZcashRpcProvider.IsAvailable(stateChanged.CryptoCode))
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"{e.CryptoCode} just became available");
|
_logger.LogInformation($"{stateChanged.CryptoCode} just became available");
|
||||||
_ = UpdateAnyPendingZcashLikePayment(e.CryptoCode);
|
_ = UpdateAnyPendingZcashLikePayment(stateChanged.CryptoCode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"{e.CryptoCode} just became unavailable");
|
_logger.LogInformation($"{stateChanged.CryptoCode} just became unavailable");
|
||||||
}
|
}
|
||||||
}));
|
}
|
||||||
_ = WorkThroughQueue(_Cts.Token);
|
else if (evt is ZcashEvent zcashEvent)
|
||||||
return Task.CompletedTask;
|
{
|
||||||
}
|
if (!_ZcashRpcProvider.IsAvailable(zcashEvent.CryptoCode))
|
||||||
|
return;
|
||||||
|
|
||||||
private async Task WorkThroughQueue(CancellationToken token)
|
if (!string.IsNullOrEmpty(zcashEvent.BlockHash))
|
||||||
{
|
|
||||||
while (await _requests.Reader.WaitToReadAsync(token) && _requests.Reader.TryRead(out var action)) {
|
|
||||||
token.ThrowIfCancellationRequested();
|
|
||||||
try {
|
|
||||||
await action.Invoke();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
{
|
||||||
_logger.LogError($"error with action item {e}");
|
await OnNewBlock(zcashEvent.CryptoCode);
|
||||||
}
|
}
|
||||||
}
|
if (!string.IsNullOrEmpty(zcashEvent.TransactionHash))
|
||||||
}
|
{
|
||||||
|
await OnTransactionUpdated(zcashEvent.CryptoCode, zcashEvent.TransactionHash);
|
||||||
private void OnZcashEvent(ZcashEvent obj)
|
|
||||||
{
|
|
||||||
if (!_ZcashRpcProvider.IsAvailable(obj.CryptoCode))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(obj.BlockHash))
|
|
||||||
{
|
|
||||||
if (!_requests.Writer.TryWrite(() => OnNewBlock(obj.CryptoCode))) {
|
|
||||||
_logger.LogWarning($"Failed to write new block task to channel");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(obj.TransactionHash))
|
|
||||||
{
|
|
||||||
if (!_requests.Writer.TryWrite(() => OnTransactionUpdated(obj.CryptoCode, obj.TransactionHash))) {
|
|
||||||
_logger.LogWarning($"Failed to write new tx task to channel");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,7 +176,7 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
|
|
||||||
var transferProcessingTasks = new List<Task>();
|
var transferProcessingTasks = new List<Task>();
|
||||||
|
|
||||||
var updatedPaymentEntities = new BlockingCollection<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
var updatedPaymentEntities = new List<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
||||||
foreach (var keyValuePair in tasks)
|
foreach (var keyValuePair in tasks)
|
||||||
{
|
{
|
||||||
var transfers = keyValuePair.Value.Result.In;
|
var transfers = keyValuePair.Value.Result.In;
|
||||||
@ -254,14 +228,6 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
leases.Dispose();
|
|
||||||
_Cts?.Cancel();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnNewBlock(string cryptoCode)
|
private async Task OnNewBlock(string cryptoCode)
|
||||||
{
|
{
|
||||||
await UpdateAnyPendingZcashLikePayment(cryptoCode);
|
await UpdateAnyPendingZcashLikePayment(cryptoCode);
|
||||||
@ -276,7 +242,7 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
"get_transfer_by_txid",
|
"get_transfer_by_txid",
|
||||||
new GetTransferByTransactionIdRequest() { TransactionId = transactionHash });
|
new GetTransferByTransactionIdRequest() { TransactionId = transactionHash });
|
||||||
|
|
||||||
var paymentsToUpdate = new BlockingCollection<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
var paymentsToUpdate = new List<(PaymentEntity Payment, InvoiceEntity invoice)>();
|
||||||
|
|
||||||
//group all destinations of the tx together and loop through the sets
|
//group all destinations of the tx together and loop through the sets
|
||||||
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
||||||
@ -315,7 +281,7 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
private async Task HandlePaymentData(string cryptoCode, string address, long totalAmount, long subaccountIndex,
|
private async Task HandlePaymentData(string cryptoCode, string address, long totalAmount, long subaccountIndex,
|
||||||
long subaddressIndex,
|
long subaddressIndex,
|
||||||
string txId, long confirmations, long blockHeight, InvoiceEntity invoice,
|
string txId, long confirmations, long blockHeight, InvoiceEntity invoice,
|
||||||
BlockingCollection<(PaymentEntity Payment, InvoiceEntity invoice)> paymentsToUpdate)
|
List<(PaymentEntity Payment, InvoiceEntity invoice)> paymentsToUpdate)
|
||||||
{
|
{
|
||||||
var network = _networkProvider.GetNetwork(cryptoCode);
|
var network = _networkProvider.GetNetwork(cryptoCode);
|
||||||
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(network.CryptoCode);
|
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(network.CryptoCode);
|
||||||
@ -329,9 +295,10 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
ConfirmationCount = confirmations,
|
ConfirmationCount = confirmations,
|
||||||
BlockHeight = blockHeight
|
BlockHeight = blockHeight
|
||||||
};
|
};
|
||||||
|
var status = GetStatus(details, invoice.SpeedPolicy) ? PaymentStatus.Settled : PaymentStatus.Processing;
|
||||||
var paymentData = new Data.PaymentData()
|
var paymentData = new Data.PaymentData()
|
||||||
{
|
{
|
||||||
Status = GetStatus(details, invoice.SpeedPolicy) ? PaymentStatus.Settled : PaymentStatus.Processing,
|
Status = status,
|
||||||
Amount = ZcashMoney.Convert(totalAmount),
|
Amount = ZcashMoney.Convert(totalAmount),
|
||||||
Created = DateTimeOffset.UtcNow,
|
Created = DateTimeOffset.UtcNow,
|
||||||
Id = $"{txId}#{subaccountIndex}#{subaddressIndex}",
|
Id = $"{txId}#{subaccountIndex}#{subaddressIndex}",
|
||||||
@ -340,11 +307,10 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
|
|
||||||
|
|
||||||
var alreadyExistingPaymentThatMatches = GetAllZcashLikePayments(invoice, cryptoCode)
|
var alreadyExistingPaymentThatMatches = GetAllZcashLikePayments(invoice, cryptoCode)
|
||||||
.Select(entity => (Payment: entity, PaymentData: handler.ParsePaymentDetails(entity.Details)))
|
.SingleOrDefault(c => c.Id == paymentData.Id && c.PaymentMethodId == pmi);
|
||||||
.SingleOrDefault(c => c.Payment.PaymentMethodId == pmi);
|
|
||||||
|
|
||||||
//if it doesnt, add it and assign a new Zcashlike address to the system if a balance is still due
|
//if it doesnt, add it and assign a new Zcashlike address to the system if a balance is still due
|
||||||
if (alreadyExistingPaymentThatMatches.Payment == null)
|
if (alreadyExistingPaymentThatMatches == null)
|
||||||
{
|
{
|
||||||
var payment = await _paymentService.AddPayment(paymentData, [txId]);
|
var payment = await _paymentService.AddPayment(paymentData, [txId]);
|
||||||
if (payment != null)
|
if (payment != null)
|
||||||
@ -353,9 +319,9 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//else update it with the new data
|
//else update it with the new data
|
||||||
alreadyExistingPaymentThatMatches.PaymentData = details;
|
alreadyExistingPaymentThatMatches.Status = status;
|
||||||
alreadyExistingPaymentThatMatches.Payment.Details = JToken.FromObject(paymentData, handler.Serializer);
|
alreadyExistingPaymentThatMatches.Details = JToken.FromObject(details, handler.Serializer);
|
||||||
paymentsToUpdate.Add((alreadyExistingPaymentThatMatches.Payment, invoice));
|
paymentsToUpdate.Add((alreadyExistingPaymentThatMatches, invoice));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,6 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
{
|
{
|
||||||
var dbPayment = dbPayments[payment.Id];
|
var dbPayment = dbPayments[payment.Id];
|
||||||
var invBlob = _invoiceRepository.ToEntity(dbPayment.InvoiceData);
|
var invBlob = _invoiceRepository.ToEntity(dbPayment.InvoiceData);
|
||||||
var dbPaymentEntity = dbPayment.GetBlob();
|
|
||||||
var wasConfirmed = dbPayment.Status is PaymentStatus.Settled;
|
var wasConfirmed = dbPayment.Status is PaymentStatus.Settled;
|
||||||
if (!wasConfirmed && payment.Status is PaymentStatus.Settled)
|
if (!wasConfirmed && payment.Status is PaymentStatus.Settled)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user