diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 95181a9e3..32df3a015 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -2,7 +2,7 @@ Exe netcoreapp2.0 - 1.0.1.49 + 1.0.1.50 NU1701,CA1816,CA1308,CA1810,CA2208 diff --git a/BTCPayServer/Extensions.cs b/BTCPayServer/Extensions.cs index 5f24c943d..a93393c42 100644 --- a/BTCPayServer/Extensions.cs +++ b/BTCPayServer/Extensions.cs @@ -30,6 +30,19 @@ namespace BTCPayServer { public static class Extensions { + public static decimal RoundUp(decimal value, int precision) + { + for (int i = 0; i < precision; i++) + { + value = value * 10m; + } + value = Math.Ceiling(value); + for (int i = 0; i < precision; i++) + { + value = value / 10m; + } + return value; + } public static PaymentMethodId GetpaymentMethodId(this InvoiceCryptoInfo info) { return new PaymentMethodId(info.CryptoCode, Enum.Parse(info.PaymentType)); diff --git a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs index e33b9a9e7..d3f2856d5 100644 --- a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs +++ b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs @@ -160,7 +160,8 @@ namespace BTCPayServer.Payments.Bitcoin if (!alreadyExist) { var payment = await _InvoiceRepository.AddPayment(invoice.Id, DateTimeOffset.UtcNow, paymentData, network.CryptoCode); - await ReceivedPayment(wallet, invoice.Id, payment, evt.DerivationStrategy); + if(payment != null) + await ReceivedPayment(wallet, invoice.Id, payment, evt.DerivationStrategy); } else { @@ -330,7 +331,8 @@ namespace BTCPayServer.Payments.Bitcoin var paymentData = new BitcoinLikePaymentData(coin.Coin, transaction.Transaction.RBF); var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin.Timestamp, paymentData, network.CryptoCode).ConfigureAwait(false); alreadyAccounted.Add(coin.Coin.Outpoint); - invoice = await ReceivedPayment(wallet, invoice.Id, payment, strategy); + if (payment != null) + invoice = await ReceivedPayment(wallet, invoice.Id, payment, strategy); totalPayment++; } } diff --git a/BTCPayServer/Payments/Lightning/ChargeListener.cs b/BTCPayServer/Payments/Lightning/ChargeListener.cs index 4f031409b..e418a4633 100644 --- a/BTCPayServer/Payments/Lightning/ChargeListener.cs +++ b/BTCPayServer/Payments/Lightning/ChargeListener.cs @@ -163,12 +163,13 @@ namespace BTCPayServer.Payments.Lightning private async Task AddPayment(BTCPayNetwork network, ChargeInvoice notification, ListenedInvoice listenedInvoice) { - await _InvoiceRepository.AddPayment(listenedInvoice.InvoiceId, notification.PaidAt.Value, new LightningLikePaymentData() + var payment = await _InvoiceRepository.AddPayment(listenedInvoice.InvoiceId, notification.PaidAt.Value, new LightningLikePaymentData() { BOLT11 = notification.PaymentRequest, Amount = notification.MilliSatoshi }, network.CryptoCode, accounted: true); - _Aggregator.Publish(new InvoiceEvent(listenedInvoice.InvoiceId, 1002, "invoice_receivedPayment")); + if(payment != null) + _Aggregator.Publish(new InvoiceEvent(listenedInvoice.InvoiceId, 1002, "invoice_receivedPayment")); } private static ChargeClient GetChargeClient(LightningSupportedPaymentMethod supportedPaymentMethod, BTCPayNetwork network) diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs index 61bc332a4..e8b852670 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs @@ -21,7 +21,7 @@ namespace BTCPayServer.Payments.Lightning public override async Task CreatePaymentMethodDetails(LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, BTCPayNetwork network) { var invoice = paymentMethod.ParentEntity; - var due = invoice.ProductInformation.Price / paymentMethod.Rate; + var due = Extensions.RoundUp(invoice.ProductInformation.Price / paymentMethod.Rate, 8); var client = GetClient(supportedPaymentMethod, network); var expiry = invoice.ExpirationTime - DateTimeOffset.UtcNow; var lightningInvoice = await client.CreateInvoiceAsync(new CreateInvoiceRequest() diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index d1eedaf5a..0730c6c18 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -646,8 +646,9 @@ namespace BTCPayServer.Services.Invoices var paid = 0m; var cryptoPaid = 0.0m; + int precision = 8; var paidTxFee = 0m; - bool paidEnough = paid >= RoundUp(totalDue, 8); + bool paidEnough = paid >= Extensions.RoundUp(totalDue, precision); int txRequired = 0; var payments = ParentEntity.GetPayments() @@ -662,7 +663,7 @@ namespace BTCPayServer.Services.Invoices totalDue += txFee; paidTxFee += txFee; } - paidEnough |= paid >= RoundUp(totalDue, 8); + paidEnough |= paid >= Extensions.RoundUp(totalDue, precision); if (GetId() == _.GetPaymentMethodId()) { cryptoPaid += _.GetCryptoPaymentData().GetValue(); @@ -681,7 +682,7 @@ namespace BTCPayServer.Services.Invoices paidTxFee += GetTxFee(); } - accounting.TotalDue = Money.Coins(RoundUp(totalDue, 8)); + accounting.TotalDue = Money.Coins(Extensions.RoundUp(totalDue, precision)); accounting.Paid = Money.Coins(paid); accounting.TxRequired = txRequired; accounting.CryptoPaid = Money.Coins(cryptoPaid); @@ -691,20 +692,6 @@ namespace BTCPayServer.Services.Invoices return accounting; } - private static decimal RoundUp(decimal value, int precision) - { - for (int i = 0; i < precision; i++) - { - value = value * 10m; - } - value = Math.Ceiling(value); - for (int i = 0; i < precision; i++) - { - value = value / 10m; - } - return value; - } - private decimal GetTxFee() { var method = GetPaymentMethodDetails(); diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index fafec2908..4dc28f7c6 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -461,6 +461,15 @@ namespace BTCPayServer.Services.Invoices AddToTextSearch(invoiceId, addresses.Select(a => a.ToString()).ToArray()); } + /// + /// Add a payment to an invoice + /// + /// + /// + /// + /// + /// + /// The PaymentEntity or null if already added public async Task AddPayment(string invoiceId, DateTimeOffset date, CryptoPaymentData paymentData, string cryptoCode, bool accounted = false) { using (var context = _ContextFactory.CreateContext()) @@ -486,7 +495,11 @@ namespace BTCPayServer.Services.Invoices context.Payments.Add(data); - await context.SaveChangesAsync().ConfigureAwait(false); + try + { + await context.SaveChangesAsync().ConfigureAwait(false); + } + catch(DbUpdateException) { return null; } // Already exists AddToTextSearch(invoiceId, paymentData.GetSearchTerms()); return entity; }