mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-04 21:36:45 +00:00
add fee rate priority indicator
This commit is contained in:
parent
13d701b0a7
commit
7ed75fc83d
5 changed files with 122 additions and 10 deletions
|
@ -1,5 +1,6 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.sparrowwallet.sparrow.wallet.SendController;
|
||||
import javafx.beans.NamedArg;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.chart.Axis;
|
||||
|
@ -27,9 +28,11 @@ public class BlockTargetFeeRatesChart extends LineChart<String, Number> {
|
|||
|
||||
for(Iterator<Integer> targetBlocksIter = targetBlocksFeeRates.keySet().iterator(); targetBlocksIter.hasNext(); ) {
|
||||
Integer targetBlocks = targetBlocksIter.next();
|
||||
String category = targetBlocks + (targetBlocksIter.hasNext() ? "" : "+");
|
||||
XYChart.Data<String, Number> data = new XYChart.Data<>(category, targetBlocksFeeRates.get(targetBlocks));
|
||||
feeRateSeries.getData().add(data);
|
||||
if(SendController.TARGET_BLOCKS_RANGE.contains(targetBlocks)) {
|
||||
String category = targetBlocks + (targetBlocksIter.hasNext() ? "" : "+");
|
||||
XYChart.Data<String, Number> data = new XYChart.Data<>(category, targetBlocksFeeRates.get(targetBlocks));
|
||||
feeRateSeries.getData().add(data);
|
||||
}
|
||||
}
|
||||
|
||||
if(selectedTargetBlocks != null) {
|
||||
|
|
|
@ -40,6 +40,7 @@ public class FontAwesome5 extends GlyphFont {
|
|||
LOCK_OPEN('\uf3c1'),
|
||||
PEN_FANCY('\uf5ac'),
|
||||
PLUS('\uf067'),
|
||||
PLUS_CIRCLE('\uf055'),
|
||||
QRCODE('\uf029'),
|
||||
QUESTION_CIRCLE('\uf059'),
|
||||
RANDOM('\uf074'),
|
||||
|
|
|
@ -40,6 +40,9 @@ public enum FeeRatesSource {
|
|||
};
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FeeRatesSource.class);
|
||||
public static final int BLOCKS_IN_HALF_HOUR = 3;
|
||||
public static final int BLOCKS_IN_HOUR = 6;
|
||||
public static final int BLOCKS_IN_TWO_HOURS = 12;
|
||||
|
||||
private final String name;
|
||||
|
||||
|
@ -61,16 +64,20 @@ public enum FeeRatesSource {
|
|||
Gson gson = new Gson();
|
||||
ThreeTierRates threeTierRates = gson.fromJson(reader, ThreeTierRates.class);
|
||||
for(Integer blockTarget : defaultblockTargetFeeRates.keySet()) {
|
||||
if(blockTarget < 3) {
|
||||
if(blockTarget < BLOCKS_IN_HALF_HOUR) {
|
||||
blockTargetFeeRates.put(blockTarget, threeTierRates.fastestFee);
|
||||
} else if(blockTarget < 6) {
|
||||
} else if(blockTarget < BLOCKS_IN_HOUR) {
|
||||
blockTargetFeeRates.put(blockTarget, threeTierRates.halfHourFee);
|
||||
} else if(blockTarget <= 10 || defaultblockTargetFeeRates.get(blockTarget) > threeTierRates.hourFee) {
|
||||
} else if(blockTarget < BLOCKS_IN_TWO_HOURS || defaultblockTargetFeeRates.get(blockTarget) > threeTierRates.hourFee) {
|
||||
blockTargetFeeRates.put(blockTarget, threeTierRates.hourFee);
|
||||
} else {
|
||||
blockTargetFeeRates.put(blockTarget, defaultblockTargetFeeRates.get(blockTarget));
|
||||
}
|
||||
}
|
||||
|
||||
if(threeTierRates.minimumFee != null) {
|
||||
blockTargetFeeRates.put(Integer.MAX_VALUE, threeTierRates.minimumFee);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Error retrieving recommended fee rates from " + url, e);
|
||||
}
|
||||
|
@ -98,5 +105,6 @@ public enum FeeRatesSource {
|
|||
Double fastestFee;
|
||||
Double halfHourFee;
|
||||
Double hourFee;
|
||||
Double minimumFee;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,11 @@ import com.sparrowwallet.sparrow.CurrencyRate;
|
|||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.*;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.net.ExchangeSource;
|
||||
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||
import com.sparrowwallet.sparrow.net.FeeRatesSource;
|
||||
import com.sparrowwallet.sparrow.net.MempoolRateSize;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.*;
|
||||
|
@ -28,6 +30,7 @@ import javafx.scene.Node;
|
|||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.util.StringConverter;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
import org.controlsfx.validation.ValidationResult;
|
||||
import org.controlsfx.validation.ValidationSupport;
|
||||
import org.controlsfx.validation.Validator;
|
||||
|
@ -79,6 +82,12 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
@FXML
|
||||
private CopyableLabel feeRate;
|
||||
|
||||
@FXML
|
||||
private Label feeRatePriority;
|
||||
|
||||
@FXML
|
||||
private Glyph feeRatePriorityGlyph;
|
||||
|
||||
@FXML
|
||||
private TextField fee;
|
||||
|
||||
|
@ -350,6 +359,8 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
addFeeRangeTrackHighlight(0);
|
||||
}
|
||||
|
||||
private void initializeTabHeader(int count) {
|
||||
|
@ -558,10 +569,12 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
Map<Integer, Double> targetBlocksFeeRates = getTargetBlocksFeeRates();
|
||||
int maxTargetBlocks = 1;
|
||||
for(Integer targetBlocks : targetBlocksFeeRates.keySet()) {
|
||||
maxTargetBlocks = Math.max(maxTargetBlocks, targetBlocks);
|
||||
Double candidate = targetBlocksFeeRates.get(targetBlocks);
|
||||
if(Math.round(feeRate) >= Math.round(candidate)) {
|
||||
return targetBlocks;
|
||||
if(TARGET_BLOCKS_RANGE.contains(targetBlocks)) {
|
||||
maxTargetBlocks = Math.max(maxTargetBlocks, targetBlocks);
|
||||
Double candidate = targetBlocksFeeRates.get(targetBlocks);
|
||||
if(Math.round(feeRate) >= Math.round(candidate)) {
|
||||
return targetBlocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -623,6 +636,45 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
|
||||
private void setFeeRate(Double feeRateAmt) {
|
||||
feeRate.setText(String.format("%.2f", feeRateAmt) + " sats/vByte");
|
||||
setFeeRatePriority(feeRateAmt);
|
||||
}
|
||||
|
||||
private void setFeeRatePriority(Double feeRateAmt) {
|
||||
Map<Integer, Double> targetBlocksFeeRates = getTargetBlocksFeeRates();
|
||||
Integer targetBlocks = getTargetBlocks(feeRateAmt);
|
||||
if(targetBlocksFeeRates.get(Integer.MAX_VALUE) != null) {
|
||||
Double minFeeRate = targetBlocksFeeRates.get(Integer.MAX_VALUE);
|
||||
if(feeRateAmt <= minFeeRate) {
|
||||
feeRatePriority.setText("Below Minimum");
|
||||
feeRatePriorityGlyph.setStyle("-fx-text-fill: #a0a1a7cc");
|
||||
feeRatePriorityGlyph.setIcon(FontAwesome5.Glyph.EXCLAMATION_CIRCLE);
|
||||
return;
|
||||
}
|
||||
|
||||
Double lowestBlocksRate = targetBlocksFeeRates.get(TARGET_BLOCKS_RANGE.get(TARGET_BLOCKS_RANGE.size() - 1));
|
||||
if(lowestBlocksRate > minFeeRate && feeRateAmt < (minFeeRate + ((lowestBlocksRate - minFeeRate) / 2))) {
|
||||
feeRatePriority.setText("Try Then Replace");
|
||||
feeRatePriorityGlyph.setStyle("-fx-text-fill: #7eb7c9cc");
|
||||
feeRatePriorityGlyph.setIcon(FontAwesome5.Glyph.PLUS_CIRCLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(targetBlocks != null) {
|
||||
if(targetBlocks < FeeRatesSource.BLOCKS_IN_HALF_HOUR) {
|
||||
feeRatePriority.setText("High Priority");
|
||||
feeRatePriorityGlyph.setStyle("-fx-text-fill: #c8416499");
|
||||
feeRatePriorityGlyph.setIcon(FontAwesome5.Glyph.CIRCLE);
|
||||
} else if(targetBlocks < FeeRatesSource.BLOCKS_IN_HOUR) {
|
||||
feeRatePriority.setText("Medium Priority");
|
||||
feeRatePriorityGlyph.setStyle("-fx-text-fill: #fba71b99");
|
||||
feeRatePriorityGlyph.setIcon(FontAwesome5.Glyph.CIRCLE);
|
||||
} else {
|
||||
feeRatePriority.setText("Low Priority");
|
||||
feeRatePriorityGlyph.setStyle("-fx-text-fill: #41a9c999");
|
||||
feeRatePriorityGlyph.setIcon(FontAwesome5.Glyph.CIRCLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Node getSliderThumb() {
|
||||
|
@ -635,6 +687,47 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
}
|
||||
}
|
||||
|
||||
private void addFeeRangeTrackHighlight(int count) {
|
||||
Platform.runLater(() -> {
|
||||
Node track = feeRange.lookup(".track");
|
||||
if(track != null) {
|
||||
Map<Integer, Double> targetBlocksFeeRates = getTargetBlocksFeeRates();
|
||||
String highlight = "";
|
||||
if(targetBlocksFeeRates.get(Integer.MAX_VALUE) != null) {
|
||||
highlight += "#a0a1a766 " + getPercentageOfFeeRange(targetBlocksFeeRates.get(Integer.MAX_VALUE)) + "%, ";
|
||||
}
|
||||
highlight += "#41a9c966 " + getPercentageOfFeeRange(targetBlocksFeeRates, FeeRatesSource.BLOCKS_IN_TWO_HOURS - 1) + "%, ";
|
||||
highlight += "#fba71b66 " + getPercentageOfFeeRange(targetBlocksFeeRates, FeeRatesSource.BLOCKS_IN_HOUR - 1) + "%, ";
|
||||
highlight += "#c8416466 " + getPercentageOfFeeRange(targetBlocksFeeRates, FeeRatesSource.BLOCKS_IN_HALF_HOUR - 1) + "%";
|
||||
|
||||
track.setStyle("-fx-background-color: " +
|
||||
"-fx-shadow-highlight-color, " +
|
||||
"linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border), " +
|
||||
"linear-gradient(to bottom, derive(-fx-control-inner-background, -9%), derive(-fx-control-inner-background, 0%), derive(-fx-control-inner-background, -5%), derive(-fx-control-inner-background, -12%)), " +
|
||||
"linear-gradient(to right, " + highlight + ")");
|
||||
} else if(count < 20) {
|
||||
addFeeRangeTrackHighlight(count+1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getPercentageOfFeeRange(Map<Integer, Double> targetBlocksFeeRates, Integer minTargetBlocks) {
|
||||
List<Integer> rates = new ArrayList<>(targetBlocksFeeRates.keySet());
|
||||
Collections.reverse(rates);
|
||||
for(Integer targetBlocks : rates) {
|
||||
if(targetBlocks < minTargetBlocks) {
|
||||
return getPercentageOfFeeRange(targetBlocksFeeRates.get(targetBlocks));
|
||||
}
|
||||
}
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
private int getPercentageOfFeeRange(Double feeRate) {
|
||||
double index = Math.log(feeRate) / Math.log(2);
|
||||
return (int)Math.round(index * 10.0);
|
||||
}
|
||||
|
||||
private void updateMaxClearButtons(UtxoSelector utxoSelector, UtxoFilter utxoFilter) {
|
||||
if(utxoSelector instanceof PresetUtxoSelector) {
|
||||
PresetUtxoSelector presetUtxoSelector = (PresetUtxoSelector)utxoSelector;
|
||||
|
@ -811,6 +904,7 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
if(targetBlocksField.isVisible()) {
|
||||
setFeeRate(event.getTargetBlockFeeRates().get(getTargetBlocks()));
|
||||
}
|
||||
addFeeRangeTrackHighlight(0);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
|
|
@ -91,6 +91,12 @@
|
|||
</Field>
|
||||
<Field fx:id="feeRateField" text="Rate:">
|
||||
<CopyableLabel fx:id="feeRate" />
|
||||
<Region HBox.hgrow="ALWAYS" />
|
||||
<Label fx:id="feeRatePriority" graphicTextGap="5">
|
||||
<graphic>
|
||||
<Glyph fx:id="feeRatePriorityGlyph" fontFamily="Font Awesome 5 Free Solid" fontSize="12" icon="CIRCLE" />
|
||||
</graphic>
|
||||
</Label>
|
||||
</Field>
|
||||
<Field text="Fee:">
|
||||
<TextField fx:id="fee" styleClass="amount-field"/>
|
||||
|
|
Loading…
Reference in a new issue