diff --git a/drongo b/drongo index 57290a20..eb49c971 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit 57290a20a143bc0f0d8440fb3c14592c2e204e6b +Subproject commit eb49c9713375ac5f909d8ec3fa4dfddaf7d63ffe diff --git a/src/main/java/com/sparrowwallet/sparrow/event/SpendUtxoEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/SpendUtxoEvent.java index 4cfc2a0d..4eb323fd 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/SpendUtxoEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/SpendUtxoEvent.java @@ -11,6 +11,7 @@ public class SpendUtxoEvent { private final Wallet wallet; private final List utxos; private final List payments; + private final List opReturns; private final Long fee; private final boolean includeSpentMempoolOutputs; private final Pool pool; @@ -23,15 +24,17 @@ public class SpendUtxoEvent { this.wallet = wallet; this.utxos = utxos; this.payments = payments; + this.opReturns = null; this.fee = fee; this.includeSpentMempoolOutputs = includeSpentMempoolOutputs; this.pool = null; } - public SpendUtxoEvent(Wallet wallet, List utxos, List payments, Long fee, Pool pool) { + public SpendUtxoEvent(Wallet wallet, List utxos, List payments, List opReturns, Long fee, Pool pool) { this.wallet = wallet; this.utxos = utxos; this.payments = payments; + this.opReturns = opReturns; this.fee = fee; this.includeSpentMempoolOutputs = false; this.pool = pool; @@ -49,6 +52,10 @@ public class SpendUtxoEvent { return payments; } + public List getOpReturns() { + return opReturns; + } + public Long getFee() { return fee; } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java index 942cacef..03797016 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/SendController.java @@ -162,6 +162,8 @@ public class SendController extends WalletFormController implements Initializabl private final BooleanProperty includeSpentMempoolOutputsProperty = new SimpleBooleanProperty(false); + private final List opReturnsList = new ArrayList<>(); + private final Set excludedChangeNodes = new HashSet<>(); private final ChangeListener feeListener = new ChangeListener<>() { @@ -556,7 +558,7 @@ public class SendController extends WalletFormController implements Initializabl boolean includeMempoolOutputs = Config.get().isIncludeMempoolOutputs(); boolean includeSpentMempoolOutputs = includeSpentMempoolOutputsProperty.get(); - walletTransactionService = new WalletTransactionService(wallet, getUtxoSelectors(payments), getUtxoFilters(), payments, excludedChangeNodes, feeRate, getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs); + walletTransactionService = new WalletTransactionService(wallet, getUtxoSelectors(payments), getUtxoFilters(), payments, opReturnsList, excludedChangeNodes, feeRate, getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs); walletTransactionService.setOnSucceeded(event -> { if(!walletTransactionService.isIgnoreResult()) { walletTransactionProperty.setValue(walletTransactionService.getValue()); @@ -616,6 +618,7 @@ public class SendController extends WalletFormController implements Initializabl private final List utxoSelectors; private final List utxoFilters; private final List payments; + private final List opReturns; private final Set excludedChangeNodes; private final double feeRate; private final double longTermFeeRate; @@ -626,11 +629,12 @@ public class SendController extends WalletFormController implements Initializabl private final boolean includeSpentMempoolOutputs; private boolean ignoreResult; - public WalletTransactionService(Wallet wallet, List utxoSelectors, List utxoFilters, List payments, Set excludedChangeNodes, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolOutputs, boolean includeSpentMempoolOutputs) { + public WalletTransactionService(Wallet wallet, List utxoSelectors, List utxoFilters, List payments, List opReturns, Set excludedChangeNodes, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolOutputs, boolean includeSpentMempoolOutputs) { this.wallet = wallet; this.utxoSelectors = utxoSelectors; this.utxoFilters = utxoFilters; this.payments = payments; + this.opReturns = opReturns; this.excludedChangeNodes = excludedChangeNodes; this.feeRate = feeRate; this.longTermFeeRate = longTermFeeRate; @@ -645,7 +649,7 @@ public class SendController extends WalletFormController implements Initializabl protected Task createTask() { return new Task<>() { protected WalletTransaction call() throws InsufficientFundsException { - return wallet.createWalletTransaction(utxoSelectors, utxoFilters, payments, excludedChangeNodes, feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs); + return wallet.createWalletTransaction(utxoSelectors, utxoFilters, payments, opReturns, excludedChangeNodes, feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs); } }; } @@ -1014,6 +1018,7 @@ public class SendController extends WalletFormController implements Initializabl utxoSelectorProperty.setValue(null); utxoFilterProperty.setValue(null); includeSpentMempoolOutputsProperty.set(false); + opReturnsList.clear(); excludedChangeNodes.clear(); walletTransactionProperty.setValue(null); createdWalletTransactionProperty.set(null); @@ -1239,6 +1244,10 @@ public class SendController extends WalletFormController implements Initializabl setPayments(List.of(payment)); } + if(event.getOpReturns() != null) { + opReturnsList.addAll(event.getOpReturns()); + } + if(event.getFee() != null) { setFeeValueSats(event.getFee()); userFeeSet.set(true); diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java index 62b671f9..4f8bc091 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/UtxosController.java @@ -320,10 +320,12 @@ public class UtxosController extends WalletFormController implements Initializab payments.add(new Payment(premixAddress, "Premix #" + i, tx0Preview.getPremixValue(), false)); } + List opReturns = List.of(new byte[64]); + final List utxos = utxoEntries.stream().map(HashIndexEntry::getHashIndex).collect(Collectors.toList()); Platform.runLater(() -> { EventManager.get().post(new SendActionEvent(getWalletForm().getWallet(), utxos)); - Platform.runLater(() -> EventManager.get().post(new SpendUtxoEvent(getWalletForm().getWallet(), utxos, payments, tx0Preview.getTx0MinerFee(), tx0Preview.getPool()))); + Platform.runLater(() -> EventManager.get().post(new SpendUtxoEvent(getWalletForm().getWallet(), utxos, payments, opReturns, tx0Preview.getTx0MinerFee(), tx0Preview.getPool()))); }); } diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java index 08dcc46f..1c0b3af4 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/Whirlpool.java @@ -71,6 +71,7 @@ public class Whirlpool { private final Tx0ParamService tx0ParamService; private final ExpirablePoolSupplier poolSupplier; private final Tx0Service tx0Service; + private Tx0FeeTarget tx0FeeTarget = Tx0FeeTarget.BLOCKS_4; private HD_Wallet hdWallet; private String walletId; private String mixToWalletId; @@ -140,7 +141,6 @@ public class Whirlpool { } private Tx0Config computeTx0Config() { - Tx0FeeTarget tx0FeeTarget = Tx0FeeTarget.BLOCKS_4; Tx0FeeTarget mixFeeTarget = Tx0FeeTarget.BLOCKS_4; return new Tx0Config(tx0ParamService, poolSupplier, tx0FeeTarget, mixFeeTarget, WhirlpoolAccount.BADBANK); } @@ -385,6 +385,14 @@ public class Whirlpool { config.setScode(scode); } + public Tx0FeeTarget getTx0FeeTarget() { + return tx0FeeTarget; + } + + public void setTx0FeeTarget(Tx0FeeTarget tx0FeeTarget) { + this.tx0FeeTarget = tx0FeeTarget; + } + public String getWalletId() { return walletId; } diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java index 3adc27aa..ba1bf96a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/WhirlpoolController.java @@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.whirlpool; import com.samourai.whirlpool.client.tx0.Tx0Preview; import com.samourai.whirlpool.client.tx0.Tx0Previews; +import com.samourai.whirlpool.client.wallet.beans.Tx0FeeTarget; import com.samourai.whirlpool.client.whirlpool.beans.Pool; import com.sparrowwallet.drongo.BitcoinUnit; import com.sparrowwallet.drongo.protocol.Transaction; @@ -10,10 +11,12 @@ import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.control.CoinLabel; +import com.sparrowwallet.sparrow.control.CopyableLabel; import com.sparrowwallet.sparrow.event.WalletMasterMixConfigChangedEvent; import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.wallet.Entry; import com.sparrowwallet.sparrow.wallet.UtxoEntry; +import com.sparrowwallet.sparrow.whirlpool.dataSource.SparrowMinerFeeSupplier; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; @@ -26,6 +29,8 @@ import javafx.util.StringConverter; import java.util.*; public class WhirlpoolController { + private static final List FEE_TARGETS = List.of(Tx0FeeTarget.MIN, Tx0FeeTarget.BLOCKS_4, Tx0FeeTarget.BLOCKS_2); + @FXML private VBox whirlpoolBox; @@ -44,6 +49,12 @@ public class WhirlpoolController { @FXML private TextField scode; + @FXML + private Slider premixPriority; + + @FXML + private CopyableLabel premixFeeRate; + @FXML private ComboBox pool; @@ -108,6 +119,30 @@ public class WhirlpoolController { EventManager.get().post(new WalletMasterMixConfigChangedEvent(wallet)); }); + premixPriority.setMin(0); + premixPriority.setMax(FEE_TARGETS.size() - 1); + premixPriority.setMajorTickUnit(1); + premixPriority.setMinorTickCount(0); + premixPriority.setLabelFormatter(new StringConverter<>() { + @Override + public String toString(Double object) { + return object.intValue() == 0 ? "Low" : (object.intValue() == 1 ? "Normal" : "High"); + } + + @Override + public Double fromString(String string) { + return null; + } + }); + premixPriority.valueProperty().addListener((observable, oldValue, newValue) -> { + pool.setItems(FXCollections.emptyObservableList()); + tx0Previews = null; + tx0PreviewProperty.set(null); + Tx0FeeTarget tx0FeeTarget = FEE_TARGETS.get(newValue.intValue()); + premixFeeRate.setText(SparrowMinerFeeSupplier.getMinimumFeeForTarget(Integer.parseInt(tx0FeeTarget.getFeeTarget().getValue())) + " sats/vB"); + }); + premixPriority.setValue(1); + if(mixConfig.getScode() != null) { step1.setVisible(false); step3.setVisible(true); @@ -280,6 +315,7 @@ public class WhirlpoolController { } else { tx0Previews = null; whirlpool.setScode(mixConfig.getScode()); + whirlpool.setTx0FeeTarget(FEE_TARGETS.get(premixPriority.valueProperty().intValue())); Whirlpool.Tx0PreviewsService tx0PreviewsService = new Whirlpool.Tx0PreviewsService(whirlpool, wallet, utxoEntries); tx0PreviewsService.setOnRunning(workerStateEvent -> { diff --git a/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowMinerFeeSupplier.java b/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowMinerFeeSupplier.java index 3eddd8a2..abdb345f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowMinerFeeSupplier.java +++ b/src/main/java/com/sparrowwallet/sparrow/whirlpool/dataSource/SparrowMinerFeeSupplier.java @@ -32,7 +32,7 @@ public class SparrowMinerFeeSupplier implements MinerFeeSupplier { return getMinimumFeeForTarget(Integer.parseInt(feeTarget.getValue())); } - private Integer getMinimumFeeForTarget(int targetBlocks) { + public static Integer getMinimumFeeForTarget(int targetBlocks) { List> feeRates = new ArrayList<>(AppServices.getTargetBlockFeeRates().entrySet()); Collections.reverse(feeRates); for(Map.Entry feeRate : feeRates) { @@ -40,6 +40,7 @@ public class SparrowMinerFeeSupplier implements MinerFeeSupplier { return feeRate.getValue().intValue(); } } + return feeRates.get(0).getValue().intValue(); } diff --git a/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.css b/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.css index dcb1e31c..d060e31e 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.css +++ b/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.css @@ -39,4 +39,8 @@ .field-label { -fx-pref-width: 120px; +} + +.field-control { + -fx-pref-width: 160px; } \ No newline at end of file diff --git a/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.fxml b/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.fxml index 3190c1f2..b5ee6dda 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.fxml +++ b/src/main/resources/com/sparrowwallet/sparrow/whirlpool/whirlpool.fxml @@ -11,6 +11,7 @@ + @@ -93,6 +94,20 @@ + + + + + + + + + +