diff --git a/BTCPayServer.Client/BTCPayServer.Client.csproj b/BTCPayServer.Client/BTCPayServer.Client.csproj index 3f2894cb0..51de680e0 100644 --- a/BTCPayServer.Client/BTCPayServer.Client.csproj +++ b/BTCPayServer.Client/BTCPayServer.Client.csproj @@ -5,7 +5,7 @@ - + diff --git a/BTCPayServer.Common/BTCPayServer.Common.csproj b/BTCPayServer.Common/BTCPayServer.Common.csproj index 6d4db4535..1908b7d92 100644 --- a/BTCPayServer.Common/BTCPayServer.Common.csproj +++ b/BTCPayServer.Common/BTCPayServer.Common.csproj @@ -4,6 +4,6 @@ - + diff --git a/BTCPayServer.Tests/docker-compose.yml b/BTCPayServer.Tests/docker-compose.yml index 5121996de..6c23f719c 100644 --- a/BTCPayServer.Tests/docker-compose.yml +++ b/BTCPayServer.Tests/docker-compose.yml @@ -78,7 +78,7 @@ services: - customer_lnd - merchant_lnd nbxplorer: - image: nicolasdorier/nbxplorer:2.1.25 + image: nicolasdorier/nbxplorer:2.1.26 restart: unless-stopped ports: - "32838:32838" diff --git a/BTCPayServer/Controllers/WalletsController.PSBT.cs b/BTCPayServer/Controllers/WalletsController.PSBT.cs index f855e9895..f7ed33e3b 100644 --- a/BTCPayServer/Controllers/WalletsController.PSBT.cs +++ b/BTCPayServer/Controllers/WalletsController.PSBT.cs @@ -44,7 +44,11 @@ namespace BTCPayServer.Controllers } psbtRequest.FeePreference = new FeePreference(); - psbtRequest.FeePreference.ExplicitFeeRate = new FeeRate(Money.Satoshis(sendModel.FeeSatoshiPerByte), 1); + if (sendModel.FeeSatoshiPerByte is decimal v && + v > decimal.Zero) + { + psbtRequest.FeePreference.ExplicitFeeRate = new FeeRate(Money.Satoshis(v), 1); + } if (sendModel.NoChange) { psbtRequest.ExplicitChangeAddress = psbtRequest.Destinations.First().Destination; diff --git a/BTCPayServer/Controllers/WalletsController.cs b/BTCPayServer/Controllers/WalletsController.cs index ce9d0a42a..3d9b56098 100644 --- a/BTCPayServer/Controllers/WalletsController.cs +++ b/BTCPayServer/Controllers/WalletsController.cs @@ -420,14 +420,35 @@ namespace BTCPayServer.Controllers var feeProvider = _feeRateProvider.CreateFeeProvider(network); - var recommendedFees = feeProvider.GetFeeRateAsync(); + var recommendedFees = new[] { + TimeSpan.FromMinutes(10.0), + TimeSpan.FromMinutes(60.0), + TimeSpan.FromHours(6.0), + TimeSpan.FromHours(24.0), + } + .Select(time => network.NBitcoinNetwork.Consensus.GetExpectedBlocksFor(time)) + .Select(blockCount => feeProvider.GetFeeRateAsync((int)blockCount)) + .ToArray(); var balance = _walletProvider.GetWallet(network).GetBalance(paymentMethod.AccountDerivation); model.NBXSeedAvailable = await CanUseHotWallet() && !string.IsNullOrEmpty(await ExplorerClientProvider.GetExplorerClient(network) .GetMetadataAsync(GetDerivationSchemeSettings(walletId).AccountDerivation, WellknownMetadataKeys.MasterHDKey)); model.CurrentBalance = await balance; - model.RecommendedSatoshiPerByte = (int)(await recommendedFees).GetFee(1).Satoshi; - model.FeeSatoshiPerByte = model.RecommendedSatoshiPerByte; + model.RecommendedSatoshiPerByte = new decimal?[recommendedFees.Length]; + for (int i = 0; i < model.RecommendedSatoshiPerByte.Length; i++) + { + decimal? feeRate = null; + try + { + feeRate = (await recommendedFees[i]).SatoshiPerByte; + } + catch + { + + } + model.RecommendedSatoshiPerByte[i] = feeRate; + } + model.FeeSatoshiPerByte = model.RecommendedSatoshiPerByte.Reverse().Where(r => r is decimal).FirstOrDefault(); model.SupportRBF = network.SupportRBF; using (CancellationTokenSource cts = new CancellationTokenSource()) { @@ -589,6 +610,25 @@ namespace BTCPayServer.Controllers "You are sending more than what you own", this); } } + if (vm.FeeSatoshiPerByte is decimal fee) + { + if (fee < 0) + { + vm.AddModelError(model => model.FeeSatoshiPerByte, + "The fee rate should be above 0", this); + } + if (fee > 5_000m) + { + vm.AddModelError(model => model.FeeSatoshiPerByte, + "The fee rate is absurdly high", this); + } + if (_dashboard.Get(network.CryptoCode).Status?.BitcoinStatus?.MinRelayTxFee?.SatoshiPerByte is decimal minFee) + { + if (vm.FeeSatoshiPerByte < minFee) + vm.AddModelError(model => model.FeeSatoshiPerByte, + $"The fee rate is lower than the minimum relay fee ({vm.FeeSatoshiPerByte} < {minFee})", this); + } + } if (!ModelState.IsValid) return View(vm); diff --git a/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs b/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs index d7fd9b4f6..ec514a300 100644 --- a/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs +++ b/BTCPayServer/Models/WalletViewModels/WalletSendModel.cs @@ -26,12 +26,18 @@ namespace BTCPayServer.Models.WalletViewModels public string CryptoCode { get; set; } - public int RecommendedSatoshiPerByte { get; set; } + public string[] RecommendedSatoshiLabels = new string[] + { + "10 minutes", + "1 hour", + "6 hours", + "1 day" + }; + public decimal?[] RecommendedSatoshiPerByte { get; set; } - [Range(1, int.MaxValue)] [Display(Name = "Fee rate (satoshi per byte)")] [Required] - public int FeeSatoshiPerByte { get; set; } + public decimal? FeeSatoshiPerByte { get; set; } [Display(Name = "Make sure no change UTXO is created")] public bool NoChange { get; set; } diff --git a/BTCPayServer/Views/Wallets/WalletSend.cshtml b/BTCPayServer/Views/Wallets/WalletSend.cshtml index 0529b0658..faf1d6c87 100644 --- a/BTCPayServer/Views/Wallets/WalletSend.cshtml +++ b/BTCPayServer/Views/Wallets/WalletSend.cshtml @@ -25,7 +25,10 @@ - + @for (int i = 0; i < Model.RecommendedSatoshiPerByte.Length; i++) + { + + } - + @if (Model.InputSelection) {
@@ -50,10 +53,10 @@ }
- +
} - + @if (Model.Outputs.Count == 1) {
@@ -130,10 +133,16 @@
+

- The recommended value is - satoshi per byte. + Target confirmation in: + @for (int i = 0; i < Model.RecommendedSatoshiPerByte.Length; i++) + { + if (Model.RecommendedSatoshiPerByte[i] is null) + continue; + . + }

@if (Model.Outputs.Count == 1) @@ -146,7 +155,7 @@
} - +
- @if (Model.CryptoCode == "BTC") { + @if (Model.CryptoCode == "BTC") + { } @if (Model.NBXSeedAvailable) @@ -202,7 +212,7 @@ }
- + diff --git a/BTCPayServer/wwwroot/js/wallet/WalletSend.js b/BTCPayServer/wwwroot/js/wallet/WalletSend.js index e5feea2f0..89c76dc01 100644 --- a/BTCPayServer/wwwroot/js/wallet/WalletSend.js +++ b/BTCPayServer/wwwroot/js/wallet/WalletSend.js @@ -27,8 +27,8 @@ function updateFiatValueWithCurrentElement() { $(function () { $(".output-amount").on("input", updateFiatValueWithCurrentElement).each(updateFiatValueWithCurrentElement); - $("#crypto-fee-link").on("click", function (elem) { - var val = $(this).text(); + $(".crypto-fee-link").on("click", function (elem) { + var val = $(this).attr("data-feerate").valueOf(); $("#FeeSatoshiPerByte").val(val); return false; }); diff --git a/Build/Version.csproj b/Build/Version.csproj index f51560b5e..e797f45ad 100644 --- a/Build/Version.csproj +++ b/Build/Version.csproj @@ -1,5 +1,5 @@ - 1.0.4.3 + 1.0.4.4