From c908301b84c46e2782811baf67b3d832cf1e66bc Mon Sep 17 00:00:00 2001 From: Umar Bolatov Date: Mon, 7 Oct 2019 21:06:12 -0700 Subject: [PATCH] Add option to show recommeded fee on checkout invoice Address #1036 --- .../BTCPayNetworkProvider.Bitcoinplus.cs | 2 +- BTCPayServer.Common/BTCPayNetwork.cs | 1 - .../Controllers/InvoiceController.UI.cs | 3 ++- BTCPayServer/Controllers/StoresController.cs | 2 ++ BTCPayServer/Data/StoreBlob.cs | 3 +++ .../Models/InvoicingModels/PaymentModel.cs | 2 ++ .../CheckoutExperienceViewModel.cs | 3 +++ .../Bitcoin/BitcoinLikeOnChainPaymentMethod.cs | 5 +++++ BTCPayServer/Payments/IPaymentMethodDetails.cs | 5 +++++ .../LightningLikePaymentMethodDetails.cs | 5 +++++ .../MoneroLikeOnChainPaymentMethodDetails.cs | 5 +++++ .../Views/Invoice/Checkout-Body.cshtml | 2 +- BTCPayServer/Views/Invoice/Checkout.cshtml | 3 +++ ...Bitcoin_Lightning_LikeMethodCheckout.cshtml | 8 +++++++- .../Views/Stores/CheckoutExperience.cshtml | 7 ++++++- .../wwwroot/checkout/css/normalizer.css | 18 ++++++++++++++++++ BTCPayServer/wwwroot/locales/en.json | 3 ++- 17 files changed, 70 insertions(+), 7 deletions(-) diff --git a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoinplus.cs b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoinplus.cs index 7a9b01b7c..08d638dd1 100644 --- a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoinplus.cs +++ b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoinplus.cs @@ -20,7 +20,7 @@ namespace BTCPayServer NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork, NBXplorerNetwork = nbxplorerNetwork, UriScheme = "bitcoinplus", - DefaultRateRules = new[] + DefaultRateRules = new[] { "XBC_X = XBC_BTC * BTC_X", "XBC_BTC = cryptopia(XBC_BTC)" diff --git a/BTCPayServer.Common/BTCPayNetwork.cs b/BTCPayServer.Common/BTCPayNetwork.cs index 00166e77c..ccb82a0a4 100644 --- a/BTCPayServer.Common/BTCPayNetwork.cs +++ b/BTCPayServer.Common/BTCPayNetwork.cs @@ -104,7 +104,6 @@ namespace BTCPayServer public abstract class BTCPayNetworkBase { - public string CryptoCode { get; internal set; } public string BlockExplorerLink { get; internal set; } public string DisplayName { get; set; } diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 90b0c4187..27e3810c6 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -225,7 +225,6 @@ namespace BTCPayServer.Controllers (1m + (changelly.AmountMarkupPercentage / 100m))) : (decimal?)null; - var paymentMethodHandler = _paymentMethodHandlerDictionary[paymentMethodId]; var model = new PaymentModel() { @@ -244,6 +243,8 @@ namespace BTCPayServer.Controllers OrderAmountFiat = OrderAmountFromInvoice(network.CryptoCode, invoice.ProductInformation), CustomerEmail = invoice.RefundMail, RequiresRefundEmail = storeBlob.RequiresRefundEmail, + ShowRecommendedFee = storeBlob.ShowRecommendedFee, + FeeRate = paymentMethodDetails.GetFeeRate(), ExpirationSeconds = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds), MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds, MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes, diff --git a/BTCPayServer/Controllers/StoresController.cs b/BTCPayServer/Controllers/StoresController.cs index 41e34f903..43b0374b0 100644 --- a/BTCPayServer/Controllers/StoresController.cs +++ b/BTCPayServer/Controllers/StoresController.cs @@ -363,6 +363,7 @@ namespace BTCPayServer.Controllers vm.HtmlTitle = storeBlob.HtmlTitle; vm.SetLanguages(_LangService, storeBlob.DefaultLang); vm.RequiresRefundEmail = storeBlob.RequiresRefundEmail; + vm.ShowRecommendedFee = storeBlob.ShowRecommendedFee; vm.OnChainMinValue = storeBlob.OnChainMinValue?.ToString() ?? ""; vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? ""; vm.LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi; @@ -421,6 +422,7 @@ namespace BTCPayServer.Controllers blob.HtmlTitle = string.IsNullOrWhiteSpace(model.HtmlTitle) ? null : model.HtmlTitle; blob.DefaultLang = model.DefaultLang; blob.RequiresRefundEmail = model.RequiresRefundEmail; + blob.ShowRecommendedFee = model.ShowRecommendedFee; blob.OnChainMinValue = onchainMinValue; blob.LightningMaxValue = lightningMaxValue; blob.LightningAmountInSatoshi = model.LightningAmountInSatoshi; diff --git a/BTCPayServer/Data/StoreBlob.cs b/BTCPayServer/Data/StoreBlob.cs index 038302457..6a7649fae 100644 --- a/BTCPayServer/Data/StoreBlob.cs +++ b/BTCPayServer/Data/StoreBlob.cs @@ -21,6 +21,7 @@ namespace BTCPayServer.Data MonitoringExpiration = 1440; PaymentTolerance = 0; RequiresRefundEmail = true; + ShowRecommendedFee = true; } [Obsolete("Use NetworkFeeMode instead")] @@ -39,6 +40,8 @@ namespace BTCPayServer.Data public bool RequiresRefundEmail { get; set; } + public bool ShowRecommendedFee { get; set; } + CurrencyPair[] _DefaultCurrencyPairs; [JsonProperty("defaultCurrencyPairs", ItemConverterType = typeof(CurrencyPairJsonConverter))] public CurrencyPair[] DefaultCurrencyPairs diff --git a/BTCPayServer/Models/InvoicingModels/PaymentModel.cs b/BTCPayServer/Models/InvoicingModels/PaymentModel.cs index ebb105fc7..280a98e80 100644 --- a/BTCPayServer/Models/InvoicingModels/PaymentModel.cs +++ b/BTCPayServer/Models/InvoicingModels/PaymentModel.cs @@ -38,6 +38,8 @@ namespace BTCPayServer.Models.InvoicingModels public string BtcDue { get; set; } public string CustomerEmail { get; set; } public bool RequiresRefundEmail { get; set; } + public bool ShowRecommendedFee { get; set; } + public decimal FeeRate { get; set; } public int ExpirationSeconds { get; set; } public string Status { get; set; } public string MerchantRefLink { get; set; } diff --git a/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs b/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs index 8d3cdb269..c2b6f1a1e 100644 --- a/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/CheckoutExperienceViewModel.cs @@ -39,6 +39,9 @@ namespace BTCPayServer.Models.StoreViewModels [Display(Name = "Requires a refund email")] public bool RequiresRefundEmail { get; set; } + [Display(Name = "Show recommended fee")] + public bool ShowRecommendedFee { get; set; } + [Display(Name = "Do not propose on chain payment if the value of the invoice is below...")] [MaxLength(20)] public string OnChainMinValue { get; set; } diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs index 58e1bd1d9..aa40009f9 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikeOnChainPaymentMethod.cs @@ -21,6 +21,11 @@ namespace BTCPayServer.Payments.Bitcoin { return NextNetworkFee.ToDecimal(MoneyUnit.BTC); } + + public decimal GetFeeRate() { + return FeeRate.SatoshiPerByte; + } + public void SetPaymentDestination(string newPaymentDestination) { DepositAddress = newPaymentDestination; diff --git a/BTCPayServer/Payments/IPaymentMethodDetails.cs b/BTCPayServer/Payments/IPaymentMethodDetails.cs index f950a833c..01d87f040 100644 --- a/BTCPayServer/Payments/IPaymentMethodDetails.cs +++ b/BTCPayServer/Payments/IPaymentMethodDetails.cs @@ -23,6 +23,11 @@ namespace BTCPayServer.Payments /// decimal GetNextNetworkFee(); /// + /// Returns recommended fee rate for a transaction + /// + /// + decimal GetFeeRate(); + /// /// Change the payment destination (internal plumbing) /// /// diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentMethodDetails.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentMethodDetails.cs index 89744930d..62b7bf965 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentMethodDetails.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentMethodDetails.cs @@ -26,6 +26,11 @@ namespace BTCPayServer.Payments.Lightning { return 0.0m; } + + public decimal GetFeeRate() { + return 0.0m; + } + public void SetPaymentDestination(string newPaymentDestination) { BOLT11 = newPaymentDestination; diff --git a/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs b/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs index a20200211..57da797ef 100644 --- a/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs +++ b/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroLikeOnChainPaymentMethodDetails.cs @@ -18,6 +18,11 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments { return NextNetworkFee; } + + public decimal GetFeeRate() { + return 0.0m; + } + public void SetPaymentDestination(string newPaymentDestination) { DepositAddress = newPaymentDestination; diff --git a/BTCPayServer/Views/Invoice/Checkout-Body.cshtml b/BTCPayServer/Views/Invoice/Checkout-Body.cshtml index ff81e860f..edf9c834c 100644 --- a/BTCPayServer/Views/Invoice/Checkout-Body.cshtml +++ b/BTCPayServer/Views/Invoice/Checkout-Body.cshtml @@ -153,7 +153,7 @@ -
+
diff --git a/BTCPayServer/Views/Invoice/Checkout.cshtml b/BTCPayServer/Views/Invoice/Checkout.cshtml index 9d9288ec2..4cc150396 100644 --- a/BTCPayServer/Views/Invoice/Checkout.cshtml +++ b/BTCPayServer/Views/Invoice/Checkout.cshtml @@ -185,6 +185,9 @@ showEmailForm: function(){ return this.srvModel.requiresRefundEmail && (!this.srvModel.customerEmail || !this.validateEmail(this.srvModel.customerEmail)) && !this.invoiceUnpayable && !this.invoicePaid; }, + showRecommendedFee: function(){ + return this.srvModel.showRecommendedFee && this.srvModel.feeRate != 0; + }, invoiceUnpayable: function(){ return ["expired", "invalid"].indexOf(this.srvModel.status) >= 0; }, diff --git a/BTCPayServer/Views/Shared/Bitcoin_Lightning_LikeMethodCheckout.cshtml b/BTCPayServer/Views/Shared/Bitcoin_Lightning_LikeMethodCheckout.cshtml index 1d134c41a..405c17c48 100644 --- a/BTCPayServer/Views/Shared/Bitcoin_Lightning_LikeMethodCheckout.cshtml +++ b/BTCPayServer/Views/Shared/Bitcoin_Lightning_LikeMethodCheckout.cshtml @@ -167,7 +167,13 @@
- } + } + + @if (Model.ShowRecommendedFee) { + + }
diff --git a/BTCPayServer/Views/Stores/CheckoutExperience.cshtml b/BTCPayServer/Views/Stores/CheckoutExperience.cshtml index 1710cc172..5ccc2e7da 100644 --- a/BTCPayServer/Views/Stores/CheckoutExperience.cshtml +++ b/BTCPayServer/Views/Stores/CheckoutExperience.cshtml @@ -65,9 +65,14 @@
- +
+
+ + +

Fee will be shown for BTC and LTC onchain payments only.

+
diff --git a/BTCPayServer/wwwroot/checkout/css/normalizer.css b/BTCPayServer/wwwroot/checkout/css/normalizer.css index 3a58f2bcf..e267f5b1e 100644 --- a/BTCPayServer/wwwroot/checkout/css/normalizer.css +++ b/BTCPayServer/wwwroot/checkout/css/normalizer.css @@ -9015,6 +9015,10 @@ strong { min-height: 393px; } +.payment-box--with-recommended-fee { + min-height: 430px; +} + .paypro { padding: 10px; } @@ -9248,6 +9252,20 @@ strong { padding-bottom: 40px; } +.recommended-fee { + box-sizing: border-box; + color: #818EA9; + font-size: 14px; + font-weight: 300; + position: absolute; + top: calc(100% - 40px); + left: 50%; + padding: 0 16px; + text-align: center; + transform: translateX(-50%); + width: 100%; +} + .success-message { color: rgba(111, 111, 111, 0.9); text-align: center; diff --git a/BTCPayServer/wwwroot/locales/en.json b/BTCPayServer/wwwroot/locales/en.json index e6f6dabdd..e00d5596d 100644 --- a/BTCPayServer/wwwroot/locales/en.json +++ b/BTCPayServer/wwwroot/locales/en.json @@ -47,5 +47,6 @@ "Pay with CoinSwitch": "Pay with CoinSwitch", "Pay with Changelly": "Pay with Changelly", "Close": "Close", - "NotPaid_ExtraTransaction": "The invoice hasn't been paid in full. Please send another transaction to cover amount Due." + "NotPaid_ExtraTransaction": "The invoice hasn't been paid in full. Please send another transaction to cover amount Due.", + "Recommended_Fee": "Recommended fee: {{feeRate}} sat/byte" } \ No newline at end of file