diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index f82a4bc0a..2bbcaba46 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -1454,7 +1454,7 @@ namespace BTCPayServer.Tests private static BTCPayRateProviderFactory CreateBTCPayRateFactory(BTCPayNetworkProvider provider) { - return new BTCPayRateProviderFactory(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromSeconds(1.0) }, provider, new CoinAverageSettings()); + return new BTCPayRateProviderFactory(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromSeconds(1.0) }, provider, null, new CoinAverageSettings()); } [Fact] diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 65beb7461..3c9101e9f 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -2,7 +2,7 @@ Exe netcoreapp2.1 - 1.0.2.13 + 1.0.2.15 NU1701,CA1816,CA1308,CA1810,CA2208 @@ -43,7 +43,7 @@ - + diff --git a/BTCPayServer/Controllers/AppsController.PointOfSale.cs b/BTCPayServer/Controllers/AppsController.PointOfSale.cs index 76b0278d1..27290739b 100644 --- a/BTCPayServer/Controllers/AppsController.PointOfSale.cs +++ b/BTCPayServer/Controllers/AppsController.PointOfSale.cs @@ -163,7 +163,7 @@ namespace BTCPayServer.Controllers [HttpPost] [Route("{appId}/pos")] [IgnoreAntiforgeryToken] - public async Task ViewPointOfSale(string appId, double amount, string choiceKey) + public async Task ViewPointOfSale(string appId, decimal amount, string choiceKey) { var app = await GetApp(appId, AppType.PointOfSale); if (string.IsNullOrEmpty(choiceKey) && amount <= 0) @@ -178,7 +178,7 @@ namespace BTCPayServer.Controllers return RedirectToAction(nameof(ViewPointOfSale), new { appId = appId }); } string title = null; - double price = 0.0; + var price = 0.0m; if (!string.IsNullOrEmpty(choiceKey)) { var choices = Parse(settings.Template, settings.Currency); @@ -186,7 +186,7 @@ namespace BTCPayServer.Controllers if (choice == null) return NotFound(); title = choice.Title; - price = (double)choice.Price.Value; + price = choice.Price.Value; } else { diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index b8d448739..f2b8b423a 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -51,7 +51,10 @@ namespace BTCPayServer.Controllers StoreLink = Url.Action(nameof(StoresController.UpdateStore), "Stores", new { storeId = store.Id }), Id = invoice.Id, Status = invoice.Status, - TransactionSpeed = invoice.SpeedPolicy == SpeedPolicy.HighSpeed ? "high" : invoice.SpeedPolicy == SpeedPolicy.MediumSpeed ? "medium" : "low", + TransactionSpeed = invoice.SpeedPolicy == SpeedPolicy.HighSpeed ? "high" : + invoice.SpeedPolicy == SpeedPolicy.MediumSpeed ? "medium" : + invoice.SpeedPolicy == SpeedPolicy.LowMediumSpeed ? "low-medium" : + "low", RefundEmail = invoice.RefundMail, CreatedDate = invoice.InvoiceTime, ExpirationDate = invoice.ExpirationTime, diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index 21f2fa83a..f10757151 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -277,6 +277,7 @@ namespace BTCPayServer.Controllers return defaultPolicy; var mappings = new Dictionary(); mappings.Add("low", SpeedPolicy.LowSpeed); + mappings.Add("low-medium", SpeedPolicy.LowMediumSpeed); mappings.Add("medium", SpeedPolicy.MediumSpeed); mappings.Add("high", SpeedPolicy.HighSpeed); if (!mappings.TryGetValue(transactionSpeed, out SpeedPolicy policy)) diff --git a/BTCPayServer/Hosting/BTCpayMiddleware.cs b/BTCPayServer/Hosting/BTCpayMiddleware.cs index bb80f20aa..a74c8d723 100644 --- a/BTCPayServer/Hosting/BTCpayMiddleware.cs +++ b/BTCPayServer/Hosting/BTCpayMiddleware.cs @@ -79,12 +79,13 @@ namespace BTCPayServer.Hosting if (!httpContext.Request.Path.HasValue) return false; + var isJson = (httpContext.Request.ContentType ?? string.Empty).StartsWith("application/json", StringComparison.OrdinalIgnoreCase); var path = httpContext.Request.Path.Value; if ( bitpayAuth && path == "/invoices" && httpContext.Request.Method == "POST" && - (httpContext.Request.ContentType ?? string.Empty).StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) + isJson) return true; if ( @@ -96,7 +97,7 @@ namespace BTCPayServer.Hosting if ( path.StartsWith("/invoices/", StringComparison.OrdinalIgnoreCase) && httpContext.Request.Method == "GET" && - (httpContext.Request.ContentType ?? string.Empty).StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) + (isJson || httpContext.Request.Query.ContainsKey("token"))) return true; if (path.Equals("/rates", StringComparison.OrdinalIgnoreCase) && diff --git a/BTCPayServer/Models/InvoicingModels/CreateInvoiceModel.cs b/BTCPayServer/Models/InvoicingModels/CreateInvoiceModel.cs index 39b77c8dc..9ac99d667 100644 --- a/BTCPayServer/Models/InvoicingModels/CreateInvoiceModel.cs +++ b/BTCPayServer/Models/InvoicingModels/CreateInvoiceModel.cs @@ -14,7 +14,7 @@ namespace BTCPayServer.Models.InvoicingModels Currency = "USD"; } [Required] - public double? Amount + public decimal? Amount { get; set; } diff --git a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs index c0d29584a..9026aaf13 100644 --- a/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs +++ b/BTCPayServer/Payments/Bitcoin/BitcoinLikePaymentData.cs @@ -68,6 +68,10 @@ namespace BTCPayServer.Payments.Bitcoin { return ConfirmationCount >= 1; } + else if (speedPolicy == SpeedPolicy.LowMediumSpeed) + { + return ConfirmationCount >= 2; + } else if (speedPolicy == SpeedPolicy.LowSpeed) { return ConfirmationCount >= 6; diff --git a/BTCPayServer/Rating/RateRules.cs b/BTCPayServer/Rating/RateRules.cs index 617a24447..d4f72618f 100644 --- a/BTCPayServer/Rating/RateRules.cs +++ b/BTCPayServer/Rating/RateRules.cs @@ -417,10 +417,21 @@ namespace BTCPayServer.Rating public RateRule(RateRules parent, CurrencyPair currencyPair, SyntaxNode candidate) { + _CurrencyPair = currencyPair; flatten = new FlattenExpressionRewriter(parent, currencyPair); this.expression = flatten.Visit(candidate); } + + private readonly CurrencyPair _CurrencyPair; + public CurrencyPair CurrencyPair + { + get + { + return _CurrencyPair; + } + } + public ExchangeRates ExchangeRates { get diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 021d3c928..ae50df206 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -101,7 +101,8 @@ namespace BTCPayServer.Services.Invoices { HighSpeed = 0, MediumSpeed = 1, - LowSpeed = 2 + LowSpeed = 2, + LowMediumSpeed = 3 } public class InvoiceEntity { diff --git a/BTCPayServer/Services/Rates/BTCPayRateProviderFactory.cs b/BTCPayServer/Services/Rates/BTCPayRateProviderFactory.cs index 91104b3ba..b115d1d30 100644 --- a/BTCPayServer/Services/Rates/BTCPayRateProviderFactory.cs +++ b/BTCPayServer/Services/Rates/BTCPayRateProviderFactory.cs @@ -35,7 +35,7 @@ namespace BTCPayServer.Services.Rates } IMemoryCache _Cache; private IOptions _CacheOptions; - + CurrencyNameTable _CurrencyTable; public IMemoryCache Cache { get @@ -46,10 +46,12 @@ namespace BTCPayServer.Services.Rates CoinAverageSettings _CoinAverageSettings; public BTCPayRateProviderFactory(IOptions cacheOptions, BTCPayNetworkProvider btcpayNetworkProvider, + CurrencyNameTable currencyTable, CoinAverageSettings coinAverageSettings) { if (cacheOptions == null) throw new ArgumentNullException(nameof(cacheOptions)); + _CurrencyTable = currencyTable; _CoinAverageSettings = coinAverageSettings; _Cache = new MemoryCache(cacheOptions); _CacheOptions = cacheOptions; @@ -161,6 +163,13 @@ namespace BTCPayServer.Services.Rates } rateRule.Reevaluate(); result.Value = rateRule.Value; + + var currencyData = _CurrencyTable?.GetCurrencyData(rateRule.CurrencyPair.Right); + if(currencyData != null && result.Value.HasValue) + { + result.Value = decimal.Round(result.Value.Value, currencyData.Divisibility, MidpointRounding.AwayFromZero); + } + result.Errors = rateRule.Errors; result.EvaluatedRule = rateRule.ToString(true); result.Rule = rateRule.ToString(false); diff --git a/BTCPayServer/Views/Apps/ViewPointOfSale.cshtml b/BTCPayServer/Views/Apps/ViewPointOfSale.cshtml index da90f297c..a4445ca83 100644 --- a/BTCPayServer/Views/Apps/ViewPointOfSale.cshtml +++ b/BTCPayServer/Views/Apps/ViewPointOfSale.cshtml @@ -19,7 +19,7 @@ @Model.Title - + @for(int i = 0; i < Model.Items.Length; i++) { @@ -36,7 +36,7 @@ { - + Pay diff --git a/BTCPayServer/Views/Stores/UpdateStore.cshtml b/BTCPayServer/Views/Stores/UpdateStore.cshtml index 1eb3f21de..9041cbe68 100644 --- a/BTCPayServer/Views/Stores/UpdateStore.cshtml +++ b/BTCPayServer/Views/Stores/UpdateStore.cshtml @@ -54,6 +54,7 @@ Is unconfirmed Has at least 1 confirmation + Has at least 2 confirmations Has at least 6 confirmations