mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-02 20:36:44 +00:00
add fee rate slider to private key sweep dialog
This commit is contained in:
parent
910a400b18
commit
30408af719
4 changed files with 149 additions and 69 deletions
|
@ -0,0 +1,102 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.net.FeeRatesSource;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sparrowwallet.sparrow.AppServices.*;
|
||||
|
||||
public class FeeRangeSlider extends Slider {
|
||||
public FeeRangeSlider() {
|
||||
super(0, FEE_RATES_RANGE.size() - 1, 0);
|
||||
setMajorTickUnit(1);
|
||||
setMinorTickCount(0);
|
||||
setSnapToTicks(false);
|
||||
setShowTickLabels(true);
|
||||
setShowTickMarks(true);
|
||||
|
||||
setLabelFormatter(new StringConverter<Double>() {
|
||||
@Override
|
||||
public String toString(Double object) {
|
||||
return Long.toString(FEE_RATES_RANGE.get(object.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
updateTrackHighlight();
|
||||
}
|
||||
|
||||
public double getFeeRate() {
|
||||
return Math.pow(2.0, getValue());
|
||||
}
|
||||
|
||||
public void setFeeRate(double feeRate) {
|
||||
setValue(Math.log(feeRate) / Math.log(2));
|
||||
}
|
||||
|
||||
public void updateTrackHighlight() {
|
||||
addFeeRangeTrackHighlight(0);
|
||||
}
|
||||
|
||||
private void addFeeRangeTrackHighlight(int count) {
|
||||
Platform.runLater(() -> {
|
||||
Node track = 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 Map<Integer, Double> getTargetBlocksFeeRates() {
|
||||
Map<Integer, Double> retrievedFeeRates = AppServices.getTargetBlockFeeRates();
|
||||
if(retrievedFeeRates == null) {
|
||||
retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> FALLBACK_FEE_RATE,
|
||||
(u, v) -> { throw new IllegalStateException("Duplicate target blocks"); },
|
||||
LinkedHashMap::new));
|
||||
}
|
||||
|
||||
return retrievedFeeRates;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.common.io.Files;
|
||||
import com.sparrowwallet.drongo.KeyPurpose;
|
||||
import com.sparrowwallet.drongo.address.Address;
|
||||
|
@ -14,6 +15,9 @@ import com.sparrowwallet.drongo.psbt.PSBT;
|
|||
import com.sparrowwallet.drongo.psbt.PSBTInput;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.UnitFormat;
|
||||
import com.sparrowwallet.sparrow.event.FeeRatesUpdatedEvent;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.io.CardApi;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
|
@ -46,10 +50,7 @@ import tornadofx.control.Form;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sparrowwallet.drongo.protocol.ScriptType.P2TR;
|
||||
|
@ -62,6 +63,8 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
|
|||
private final CopyableLabel keyAddress;
|
||||
private final ComboBoxTextField toAddress;
|
||||
private final ComboBox<Wallet> toWallet;
|
||||
private final FeeRangeSlider feeRange;
|
||||
private final CopyableLabel feeRate;
|
||||
|
||||
public PrivateKeySweepDialog(Wallet wallet) {
|
||||
final DialogPane dialogPane = getDialogPane();
|
||||
|
@ -146,7 +149,24 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
|
|||
stackPane.getChildren().addAll(toWallet, toAddress);
|
||||
toAddressField.getInputs().add(stackPane);
|
||||
|
||||
fieldset.getChildren().addAll(keyField, keyScriptTypeField, addressField, toAddressField);
|
||||
Field feeRangeField = new Field();
|
||||
feeRangeField.setText("Fee range:");
|
||||
feeRange = new FeeRangeSlider();
|
||||
feeRange.setMaxWidth(320);
|
||||
feeRangeField.getInputs().add(feeRange);
|
||||
|
||||
Field feeRateField = new Field();
|
||||
feeRateField.setText("Fee rate:");
|
||||
feeRate = new CopyableLabel();
|
||||
feeRateField.getInputs().add(feeRate);
|
||||
|
||||
feeRange.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
updateFeeRate();
|
||||
});
|
||||
feeRange.setFeeRate(AppServices.getDefaultFeeRate());
|
||||
updateFeeRate();
|
||||
|
||||
fieldset.getChildren().addAll(keyField, keyScriptTypeField, addressField, toAddressField, feeRangeField, feeRateField);
|
||||
form.getChildren().add(fieldset);
|
||||
dialogPane.setContent(form);
|
||||
|
||||
|
@ -201,6 +221,11 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
|
|||
setResultConverter(dialogButton -> null);
|
||||
dialogPane.setPrefWidth(680);
|
||||
|
||||
EventManager.get().register(this);
|
||||
setOnCloseRequest(event -> {
|
||||
EventManager.get().unregister(this);
|
||||
});
|
||||
|
||||
ValidationSupport validationSupport = new ValidationSupport();
|
||||
Platform.runLater(() -> {
|
||||
validationSupport.setValidationDecorator(new StyleClassValidationDecoration());
|
||||
|
@ -357,7 +382,7 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
|
|||
TransactionOutput sweepOutput = new TransactionOutput(noFeeTransaction, total, destAddress.getOutputScript());
|
||||
noFeeTransaction.addOutput(sweepOutput);
|
||||
|
||||
Double feeRate = AppServices.getDefaultFeeRate();
|
||||
double feeRate = feeRange.getFeeRate();
|
||||
long fee = (long)Math.ceil(noFeeTransaction.getVirtualSize() * feeRate);
|
||||
if(feeRate == Transaction.DEFAULT_MIN_RELAY_FEE) {
|
||||
fee++;
|
||||
|
@ -425,6 +450,16 @@ public class PrivateKeySweepDialog extends Dialog<Transaction> {
|
|||
return glyph;
|
||||
}
|
||||
|
||||
private void updateFeeRate() {
|
||||
UnitFormat format = Config.get().getUnitFormat() == null ? UnitFormat.DOT : Config.get().getUnitFormat();
|
||||
feeRate.setText(format.getCurrencyFormat().format(feeRange.getFeeRate()) + " sats/vB");
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void feeRatesUpdated(FeeRatesUpdatedEvent event) {
|
||||
feeRange.updateTrackHighlight();
|
||||
}
|
||||
|
||||
public class PassphraseDialog extends Dialog<String> {
|
||||
private final CustomPasswordField passphrase;
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
private Field feeRangeField;
|
||||
|
||||
@FXML
|
||||
private Slider feeRange;
|
||||
private FeeRangeSlider feeRange;
|
||||
|
||||
@FXML
|
||||
private CopyableLabel feeRate;
|
||||
|
@ -306,21 +306,6 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
|
||||
feeRangeField.managedProperty().bind(feeRangeField.visibleProperty());
|
||||
feeRangeField.visibleProperty().bind(targetBlocksField.visibleProperty().not());
|
||||
feeRange.setMin(0);
|
||||
feeRange.setMax(FEE_RATES_RANGE.size() - 1);
|
||||
feeRange.setMajorTickUnit(1);
|
||||
feeRange.setMinorTickCount(0);
|
||||
feeRange.setLabelFormatter(new StringConverter<Double>() {
|
||||
@Override
|
||||
public String toString(Double object) {
|
||||
return Long.toString(FEE_RATES_RANGE.get(object.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
feeRange.valueProperty().addListener(feeRangeListener);
|
||||
|
||||
blockTargetFeeRatesChart.managedProperty().bind(blockTargetFeeRatesChart.visibleProperty());
|
||||
|
@ -424,8 +409,6 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
}
|
||||
});
|
||||
|
||||
addFeeRangeTrackHighlight(0);
|
||||
|
||||
efficiencyToggle.setOnAction(event -> {
|
||||
if(StandardAccount.WHIRLPOOL_MIX_ACCOUNTS.contains(getWalletForm().getWallet().getStandardAccountType()) && !overrideOptimizationStrategy) {
|
||||
AppServices.showWarningDialog("Privacy may be lost!", "It is recommended to optimize for privacy when sending coinjoined outputs.");
|
||||
|
@ -846,12 +829,12 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
}
|
||||
|
||||
private Double getFeeRangeRate() {
|
||||
return Math.pow(2.0, feeRange.getValue());
|
||||
return feeRange.getFeeRate();
|
||||
}
|
||||
|
||||
private void setFeeRangeRate(Double feeRate) {
|
||||
feeRange.valueProperty().removeListener(feeRangeListener);
|
||||
feeRange.setValue(Math.log(feeRate) / Math.log(2));
|
||||
feeRange.setFeeRate(feeRate);
|
||||
feeRange.valueProperty().addListener(feeRangeListener);
|
||||
}
|
||||
|
||||
|
@ -981,47 +964,6 @@ 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, TxoFilter txoFilter) {
|
||||
if(utxoSelector instanceof PresetUtxoSelector presetUtxoSelector) {
|
||||
int num = presetUtxoSelector.getPresetUtxos().size();
|
||||
|
@ -1507,7 +1449,7 @@ public class SendController extends WalletFormController implements Initializabl
|
|||
} else {
|
||||
setFeeRatePriority(getFeeRangeRate());
|
||||
}
|
||||
addFeeRangeTrackHighlight(0);
|
||||
feeRange.updateTrackHighlight();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<?import com.sparrowwallet.sparrow.wallet.FeeRatesSelection?>
|
||||
<?import com.sparrowwallet.sparrow.wallet.OptimizationStrategy?>
|
||||
<?import com.sparrowwallet.sparrow.control.HelpLabel?>
|
||||
<?import com.sparrowwallet.sparrow.control.FeeRangeSlider?>
|
||||
|
||||
<BorderPane stylesheets="@send.css, @wallet.css, @../script.css, @../general.css" styleClass="wallet-pane" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sparrowwallet.sparrow.wallet.SendController">
|
||||
<center>
|
||||
|
@ -88,7 +89,7 @@
|
|||
<Slider fx:id="targetBlocks" snapToTicks="true" showTickLabels="true" showTickMarks="true" />
|
||||
</Field>
|
||||
<Field fx:id="feeRangeField" text="Range:">
|
||||
<Slider fx:id="feeRange" snapToTicks="false" showTickLabels="true" showTickMarks="true" />
|
||||
<FeeRangeSlider fx:id="feeRange" />
|
||||
</Field>
|
||||
<Field fx:id="feeRateField" text="Rate:">
|
||||
<CopyableLabel fx:id="feeRate" />
|
||||
|
|
Loading…
Reference in a new issue