diff --git a/src/main/java/com/sparrowwallet/sparrow/AppServices.java b/src/main/java/com/sparrowwallet/sparrow/AppServices.java index 6b8d29ce..be1e776d 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppServices.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppServices.java @@ -16,7 +16,6 @@ import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.sparrow.control.DialogImage; import com.sparrowwallet.sparrow.control.WalletPasswordDialog; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; -import com.sparrowwallet.sparrow.net.Auth47; import com.sparrowwallet.drongo.protocol.BlockHeader; import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.Transaction; @@ -71,6 +70,7 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.sparrowwallet.sparrow.control.DownloadVerifierDialog.*; @@ -91,8 +91,11 @@ public class AppServices { private static final String TOR_DEFAULT_PROXY_CIRCUIT_ID = "default"; public static final List TARGET_BLOCKS_RANGE = List.of(1, 2, 3, 4, 5, 10, 25, 50); - public static final List DOUBLE_FEE_RATES_RANGE = List.of(0.01D, 0.05D, 0.1D, 0.5, 1D, 2D, 4D, 8D, 16D, 32D, 64D, 128D, 256D, 512D, 1024D, 2048D, 4096D, 8192D); - public static final List FEE_RATES_RANGE = DOUBLE_FEE_RATES_RANGE.subList(0, DOUBLE_FEE_RATES_RANGE.size() - 8); + public static final List DOUBLE_FEE_MIN_RATES_RANGE = List.of(0.01D, 0.05D, 0.1D, 0.5); + public static final List DOUBLE_FEE_RATES_RANGE = List.of(1D, 2D, 4D, 8D, 16D, 32D, 64D, 128D, 256D, 512D, 1024D, 2048D, 4096D, 8192D); + public static final List FULL_DOUBLE_FEE_RATES_RANGE = Stream.concat(DOUBLE_FEE_MIN_RATES_RANGE.stream(), DOUBLE_FEE_RATES_RANGE.stream()).toList(); + public static final List FEE_RATES_RANGE = DOUBLE_FEE_RATES_RANGE.subList(0, DOUBLE_FEE_RATES_RANGE.size() - 4); + public static final List FULL_FEE_RATES_RANGE = FULL_DOUBLE_FEE_RATES_RANGE.subList(0, FULL_DOUBLE_FEE_RATES_RANGE.size() - 8); public static final double FALLBACK_FEE_RATE = 20000d / 1000; public static final double TESTNET_FALLBACK_FEE_RATE = 1000d / 1000; @@ -792,6 +795,24 @@ public class AppServices { return minimumRelayFeeRate == null ? Transaction.DEFAULT_MIN_RELAY_FEE : minimumRelayFeeRate; } + public static List getDoubleFeeRatesRange() { + if (AppServices.getMinimumRelayFeeRate() == 0.01) { + return FULL_DOUBLE_FEE_RATES_RANGE; + } + return DOUBLE_FEE_RATES_RANGE; + } + + public static List getFeeRatesRange() { + if (isFullFeeRatesRange()) { + return FULL_FEE_RATES_RANGE; + } + return FEE_RATES_RANGE; + } + + public static boolean isFullFeeRatesRange() { + return getDoubleFeeRatesRange().size() == FULL_DOUBLE_FEE_RATES_RANGE.size(); + } + public static CurrencyRate getFiatCurrencyExchangeRate() { return fiatCurrencyExchangeRate; } @@ -1219,7 +1240,7 @@ public class AppServices { public void newConnection(ConnectionEvent event) { currentBlockHeight = event.getBlockHeight(); System.setProperty(Network.BLOCK_HEIGHT_PROPERTY, Integer.toString(currentBlockHeight)); - minimumRelayFeeRate = Math.max(event.getMinimumRelayFeeRate(), Transaction.DEFAULT_MIN_RELAY_FEE); + minimumRelayFeeRate = Math.min(event.getMinimumRelayFeeRate(), Transaction.DEFAULT_MIN_RELAY_FEE); latestBlockHeader = event.getBlockHeader(); Config.get().addRecentServer(); diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java b/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java index 11a869a6..0cae987c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java @@ -16,7 +16,7 @@ public class FeeRangeSlider extends Slider { private static final double FEE_RATE_SCROLL_INCREMENT = 0.01; public FeeRangeSlider() { - super(0, FEE_RATES_RANGE.size() - 1, 0); + super(0, getFeeRatesRange().size() - 1, 0); setMajorTickUnit(1); setMinorTickCount(0); setSnapToTicks(false); @@ -27,7 +27,7 @@ public class FeeRangeSlider extends Slider { setLabelFormatter(new StringConverter<>() { @Override public String toString(Double object) { - Double feeRate = DOUBLE_FEE_RATES_RANGE.get(object.intValue()); + Double feeRate = getDoubleFeeRatesRange().get(object.intValue()); if(isDoubleFeeRange() && feeRate >= 1000) { return feeRate.longValue() / 1000 + "k"; } @@ -51,10 +51,10 @@ public class FeeRangeSlider extends Slider { setOnScroll(event -> { if(event.getDeltaY() != 0) { double newFeeRate = getFeeRate() + (event.getDeltaY() > 0 ? FEE_RATE_SCROLL_INCREMENT : -FEE_RATE_SCROLL_INCREMENT); - if(newFeeRate < DOUBLE_FEE_RATES_RANGE.get(0)) { - newFeeRate = DOUBLE_FEE_RATES_RANGE.get(0); - } else if(newFeeRate > DOUBLE_FEE_RATES_RANGE.get(DOUBLE_FEE_RATES_RANGE.size() - 1)) { - newFeeRate = DOUBLE_FEE_RATES_RANGE.get(DOUBLE_FEE_RATES_RANGE.size() - 1); + if(newFeeRate < getDoubleFeeRatesRange().get(0)) { + newFeeRate = getDoubleFeeRatesRange().get(0); + } else if(newFeeRate > getDoubleFeeRatesRange().get(getDoubleFeeRatesRange().size() - 1)) { + newFeeRate = getDoubleFeeRatesRange().get(getDoubleFeeRatesRange().size() - 1); } setFeeRate(newFeeRate); } @@ -63,14 +63,18 @@ public class FeeRangeSlider extends Slider { public double getFeeRate() { double value = getValue(); - // First range: 0.01, 0.05, 0.1 - if(value < 1) return 0.01 + (0.05 - 0.01) * value; - if(value < 2) return 0.05 + (0.1 - 0.05) * (value - 1); - // Second range: 0.1, 0.5, 1 - if(value < 3) return 0.1 + (0.5 - 0.1) * (value - 2); - if(value < 4) return 0.5 + (1.0 - 0.5) * (value - 3); - // Third range: 1, 2, 4, 8, ... - return Math.pow(2, value - 4 + 0) * 1.0; + if (isFullFeeRatesRange()) { + // First range: 0.01, 0.05, 0.1 + if(value < 1) return 0.01 + (0.05 - 0.01) * value; + if(value < 2) return 0.05 + (0.1 - 0.05) * (value - 1); + // Second range: 0.1, 0.5, 1 + if(value < 3) return 0.1 + (0.5 - 0.1) * (value - 2); + if(value < 4) return 0.5 + (1.0 - 0.5) * (value - 3); + // Third range: 1, 2, 4, 8, ... + return Math.pow(2, value - 4 + 0) * 1.0; + } + + return Math.pow(2.0, value); } public void setFeeRate(double feeRate) { @@ -81,18 +85,18 @@ public class FeeRangeSlider extends Slider { private void updateMaxFeeRange(double value) { if(value >= getMax() && !isDoubleFeeRange()) { - setMin(FEE_RATES_RANGE.size() - 2); - setMax(DOUBLE_FEE_RATES_RANGE.size() - 1); + setMin(getFeeRatesRange().size() - 2); + setMax(getDoubleFeeRatesRange().size() - 1); updateTrackHighlight(); } else if(value == getMin() && isDoubleFeeRange()) { setMin(0); - setMax(FEE_RATES_RANGE.size() - 1); + setMax(getFeeRatesRange().size() - 1); updateTrackHighlight(); } } private boolean isDoubleFeeRange() { - return getMax() > FEE_RATES_RANGE.size() - 1; + return getMax() > getFeeRatesRange().size() - 1; } public void updateTrackHighlight() { @@ -149,7 +153,7 @@ public class FeeRangeSlider extends Slider { private int getPercentageOfFeeRange(Double feeRate) { double index = Math.log(feeRate) / Math.log(2); if(isDoubleFeeRange()) { - index *= ((double)FEE_RATES_RANGE.size() / (DOUBLE_FEE_RATES_RANGE.size())) * 0.99; + index *= ((double)getFeeRatesRange().size() / (getDoubleFeeRatesRange().size())) * 0.99; } return (int)Math.round(index * 10.0); } diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java index d0125814..9d3c0155 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java @@ -1139,7 +1139,7 @@ public class HeadersController extends TransactionFormController implements Init if(fee.getValue() > 0) { double feeRateAmt = fee.getValue() / headersForm.getTransaction().getVirtualSize(); - if(feeRateAmt > AppServices.DOUBLE_FEE_RATES_RANGE.get(AppServices.DOUBLE_FEE_RATES_RANGE.size() - 1)) { + if(feeRateAmt > AppServices.getDoubleFeeRatesRange().get(AppServices.getDoubleFeeRatesRange().size() - 1)) { Optional optType = AppServices.showWarningDialog("Very high fee rate!", "This transaction pays a very high fee rate of " + String.format("%.0f", feeRateAmt) + " sats/vB.\n\nBroadcast this transaction?", ButtonType.YES, ButtonType.NO); if(optType.isPresent() && optType.get() == ButtonType.NO) { diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java index 452bbaac..481c6cf5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java @@ -950,7 +950,7 @@ public class SendController extends WalletFormController implements Initializabl Map targetBlocksFeeRates = getTargetBlocksFeeRates(); if(targetBlocksFeeRates.get(Integer.MAX_VALUE) != null) { Double minFeeRate = targetBlocksFeeRates.get(Integer.MAX_VALUE); - if(feeRateAmt > 0.01 && feeRateAmt < minFeeRate) { + if(feeRateAmt > getMinimumRelayFeeRate() && feeRateAmt < minFeeRate) { feeRatePriority.setText("Below Minimum"); feeRatePriority.setTooltip(new Tooltip("Transactions at this fee rate can be purged from mempool")); feeRatePriorityGlyph.setStyle("-fx-text-fill: #a0a1a7cc"); @@ -971,7 +971,7 @@ public class SendController extends WalletFormController implements Initializabl Integer targetBlocks = getTargetBlocks(feeRateAmt); if(targetBlocks != null) { if(targetBlocks < FeeRatesSource.BLOCKS_IN_HALF_HOUR) { - Double maxFeeRate = FEE_RATES_RANGE.get(FEE_RATES_RANGE.size() - 1).doubleValue(); + Double maxFeeRate = getFeeRatesRange().get(getFeeRatesRange().size() - 1).doubleValue(); Double highestBlocksRate = targetBlocksFeeRates.get(TARGET_BLOCKS_RANGE.get(0)); if(highestBlocksRate < maxFeeRate && feeRateAmt > (highestBlocksRate + ((maxFeeRate - highestBlocksRate) / 10))) { feeRatePriority.setText("Overpaid");