diff --git a/BTCPayServer/Controllers/UIInvoiceController.UI.cs b/BTCPayServer/Controllers/UIInvoiceController.UI.cs index 0f51a1118..ae594d3cf 100644 --- a/BTCPayServer/Controllers/UIInvoiceController.UI.cs +++ b/BTCPayServer/Controllers/UIInvoiceController.UI.cs @@ -875,13 +875,7 @@ namespace BTCPayServer.Controllers return extension?.Image ?? ""; } - var cd = this._CurrencyNameTable.GetCurrencyData(prompt.Currency, false); - // Show the "Common divisibility" rather than the payment method disibility. - // For example, BTC has commonly 8 digits, but on lightning it has 11. In this case, pick 8. - if (cd?.Divisibility is not int divisibility) - divisibility = prompt.Divisibility; - - string ShowMoney(decimal value) => MoneyExtensions.ShowMoney(value, divisibility); + string ShowMoney(decimal value) => MoneyExtensions.ShowMoney(value, prompt.RateDivisibility ?? prompt.Divisibility); var model = new PaymentModel { Activated = prompt.Activated, diff --git a/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs b/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs index aa42fc565..9ddc05108 100644 --- a/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs +++ b/BTCPayServer/Payments/LNURLPay/LNURLPayPaymentHandler.cs @@ -53,6 +53,7 @@ namespace BTCPayServer.Payments.Lightning context.Prompt.Inactive = false; context.Prompt.Currency = _network.CryptoCode; context.Prompt.Divisibility = 11; + context.Prompt.RateDivisibility = 8; context.Prompt.PaymentMethodFee = 0.0m; return Task.CompletedTask; } diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs index ccf9f8361..3bca13009 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs @@ -62,6 +62,7 @@ namespace BTCPayServer.Payments.Lightning context.Prompt.Currency = _Network.CryptoCode; context.Prompt.PaymentMethodFee = 0m; context.Prompt.Divisibility = 11; + context.Prompt.RateDivisibility = 8; return Task.CompletedTask; } diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 842025ec7..b8ec55855 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -870,8 +870,16 @@ namespace BTCPayServer.Services.Invoices public string Currency { get; set; } [JsonIgnore] public decimal Rate => Currency is null ? throw new InvalidOperationException("Currency of the payment prompt isn't set") : ParentEntity.GetInvoiceRate(Currency); + /// + /// The maximum divisibility supported by the underlying payment method + /// public int Divisibility { get; set; } /// + /// The divisibility to use when calculating the amount to pay. + /// If null, it will use the . + /// + public int? RateDivisibility { get; set; } + /// /// Total additional fee imposed by this specific payment method. /// It includes the . /// @@ -909,24 +917,25 @@ namespace BTCPayServer.Services.Invoices accounting.TxRequired = accounting.TxCount; var grossDue = i.Price + i.PaidFee; var rate = Rate; + var divisibility = RateDivisibility ?? Divisibility; if (i.MinimumNetDue > 0.0m) { accounting.TxRequired++; grossDue += rate * PaymentMethodFee; } - accounting.TotalDue = Coins(grossDue / rate, Divisibility); - accounting.Paid = Coins(i.PaidAmount.Gross / rate, Divisibility); - accounting.PaymentMethodPaid = Coins(thisPaymentMethodPayments.Sum(p => p.PaidAmount.Gross), Divisibility); + accounting.TotalDue = Coins(grossDue / rate, divisibility); + accounting.Paid = Coins(i.PaidAmount.Gross / rate, divisibility); + accounting.PaymentMethodPaid = Coins(thisPaymentMethodPayments.Sum(p => p.PaidAmount.Gross), divisibility); // This one deal with the fact where it might looks like a slight over payment due to the dust of another payment method. // So if we detect the NetDue is zero, just cap dueUncapped to 0 var dueUncapped = i.NetDue == 0.0m ? 0.0m : grossDue - i.PaidAmount.Gross; - accounting.DueUncapped = Coins(dueUncapped / rate, Divisibility); + accounting.DueUncapped = Coins(dueUncapped / rate, divisibility); accounting.Due = Max(accounting.DueUncapped, 0.0m); - accounting.PaymentMethodFee = Coins((grossDue - i.Price) / rate, Divisibility); + accounting.PaymentMethodFee = Coins((grossDue - i.Price) / rate, divisibility); - accounting.MinimumTotalDue = Max(Smallest(Divisibility), Coins((grossDue * (1.0m - ((decimal)i.PaymentTolerance / 100.0m))) / rate, Divisibility)); + accounting.MinimumTotalDue = Max(Smallest(divisibility), Coins((grossDue * (1.0m - ((decimal)i.PaymentTolerance / 100.0m))) / rate, divisibility)); return accounting; }