diff --git a/src/main/java/com/sparrowwallet/sparrow/AppServices.java b/src/main/java/com/sparrowwallet/sparrow/AppServices.java index 960fcf48..f35dbb4d 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppServices.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppServices.java @@ -83,8 +83,10 @@ 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 FEE_RATES_RANGE = List.of(1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L, 256L, 512L, 1024L); + public static final List LONG_FEE_RATES_RANGE = List.of(1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L, 256L, 512L, 1024L, 2048L, 4096L, 8192L); + public static final List FEE_RATES_RANGE = LONG_FEE_RATES_RANGE.subList(0, LONG_FEE_RATES_RANGE.size() - 3); public static final double FALLBACK_FEE_RATE = 20000d / 1000; + public static final double TESTNET_FALLBACK_FEE_RATE = 1000d / 1000; private static AppServices INSTANCE; @@ -660,15 +662,19 @@ public class AppServices { public static Double getDefaultFeeRate() { int defaultTarget = TARGET_BLOCKS_RANGE.get((TARGET_BLOCKS_RANGE.size() / 2) - 1); - return getTargetBlockFeeRates() == null ? FALLBACK_FEE_RATE : getTargetBlockFeeRates().get(defaultTarget); + return getTargetBlockFeeRates() == null ? getFallbackFeeRate() : getTargetBlockFeeRates().get(defaultTarget); } public static Double getMinimumFeeRate() { Optional optMinFeeRate = getTargetBlockFeeRates().values().stream().min(Double::compareTo); - Double minRate = optMinFeeRate.orElse(FALLBACK_FEE_RATE); + Double minRate = optMinFeeRate.orElse(getFallbackFeeRate()); return Math.max(minRate, Transaction.DUST_RELAY_TX_FEE); } + public static double getFallbackFeeRate() { + return Network.get() == Network.MAINNET ? FALLBACK_FEE_RATE : TESTNET_FALLBACK_FEE_RATE; + } + public static Map getTargetBlockFeeRates() { return targetBlockFeeRates; } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java b/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java index 0777ad6d..1347b9b0 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/FeeRangeSlider.java @@ -22,10 +22,14 @@ public class FeeRangeSlider extends Slider { setShowTickMarks(true); setBlockIncrement(Math.log(1.02) / Math.log(2)); - setLabelFormatter(new StringConverter() { + setLabelFormatter(new StringConverter<>() { @Override public String toString(Double object) { - return Long.toString(FEE_RATES_RANGE.get(object.intValue())); + Long feeRate = LONG_FEE_RATES_RANGE.get(object.intValue()); + if(isLongFeeRange() && feeRate >= 1000) { + return feeRate / 1000 + "k"; + } + return Long.toString(feeRate); } @Override @@ -35,6 +39,12 @@ public class FeeRangeSlider extends Slider { }); updateTrackHighlight(); + + valueProperty().addListener((observable, oldValue, newValue) -> { + if(newValue != null) { + updateMaxFeeRange(newValue.doubleValue()); + } + }); } public double getFeeRate() { @@ -42,7 +52,23 @@ public class FeeRangeSlider extends Slider { } public void setFeeRate(double feeRate) { - setValue(Math.log(feeRate) / Math.log(2)); + double value = Math.log(feeRate) / Math.log(2); + updateMaxFeeRange(value); + setValue(value); + } + + private void updateMaxFeeRange(double value) { + if(value >= getMax() && !isLongFeeRange()) { + setMax(LONG_FEE_RATES_RANGE.size() - 1); + updateTrackHighlight(); + } else if(value == getMin() && isLongFeeRange()) { + setMax(FEE_RATES_RANGE.size() - 1); + updateTrackHighlight(); + } + } + + private boolean isLongFeeRange() { + return getMax() > FEE_RATES_RANGE.size() - 1; } public void updateTrackHighlight() { @@ -76,7 +102,7 @@ public class FeeRangeSlider extends Slider { private Map getTargetBlocksFeeRates() { Map retrievedFeeRates = AppServices.getTargetBlockFeeRates(); if(retrievedFeeRates == null) { - retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> FALLBACK_FEE_RATE, + retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> getFallbackFeeRate(), (u, v) -> { throw new IllegalStateException("Duplicate target blocks"); }, LinkedHashMap::new)); } @@ -98,6 +124,9 @@ public class FeeRangeSlider extends Slider { private int getPercentageOfFeeRange(Double feeRate) { double index = Math.log(feeRate) / Math.log(2); + if(isLongFeeRange()) { + index *= ((double)FEE_RATES_RANGE.size() / (LONG_FEE_RATES_RANGE.size())) * 0.99; + } return (int)Math.round(index * 10.0); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java index 59b2e95f..6ec16afa 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java @@ -4,6 +4,7 @@ import com.google.common.eventbus.Subscribe; import com.samourai.whirlpool.client.whirlpool.beans.Pool; import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.KeyPurpose; +import com.sparrowwallet.drongo.Network; import com.sparrowwallet.drongo.SecureString; import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.InvalidAddressException; @@ -243,6 +244,8 @@ public class SendController extends WalletFormController implements Initializabl private boolean overrideOptimizationStrategy; + private boolean updateDefaultFeeRate; + @Override public void initialize(URL location, ResourceBundle resources) { EventManager.get().register(this); @@ -757,6 +760,10 @@ public class SendController extends WalletFormController implements Initializabl blockTargetFeeRatesChart.select(defaultTarget); setFeeRangeRate(defaultRate); setFeeRate(getFeeRangeRate()); + if(Network.get().equals(Network.MAINNET) && defaultRate == getFallbackFeeRate()) { + //Update the selected fee rate once fee rates have been received + updateDefaultFeeRate = true; + } } private Long getFeeValueSats() { @@ -821,7 +828,7 @@ public class SendController extends WalletFormController implements Initializabl private Map getTargetBlocksFeeRates() { Map retrievedFeeRates = AppServices.getTargetBlockFeeRates(); if(retrievedFeeRates == null) { - retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> FALLBACK_FEE_RATE, + retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> getFallbackFeeRate(), (u, v) -> { throw new IllegalStateException("Duplicate target blocks"); }, LinkedHashMap::new)); } @@ -860,7 +867,7 @@ public class SendController extends WalletFormController implements Initializabl private Double getMinimumFeeRate() { Optional optMinFeeRate = getTargetBlocksFeeRates().values().stream().min(Double::compareTo); - Double minRate = optMinFeeRate.orElse(FALLBACK_FEE_RATE); + Double minRate = optMinFeeRate.orElse(getFallbackFeeRate()); return Math.max(minRate, Transaction.DUST_RELAY_TX_FEE); } @@ -1451,6 +1458,11 @@ public class SendController extends WalletFormController implements Initializabl setFeeRatePriority(getFeeRangeRate()); } feeRange.updateTrackHighlight(); + + if(updateDefaultFeeRate) { + setDefaultFeeRate(); + updateDefaultFeeRate = false; + } } @Subscribe