mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-05 05:46:44 +00:00
disable privacy optimisation button for payjoins, improve rbf behaviour for wallet sweep txes
This commit is contained in:
parent
5e4d6d5a78
commit
218761c594
6 changed files with 24 additions and 6 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit ba8692450335f2e5293ddd3951a394244315803f
|
Subproject commit eddd6406efc20b83e659d59faa16189417b0f5ed
|
|
@ -690,6 +690,10 @@ public class AppServices {
|
||||||
payjoinURIs.put(bitcoinURI.getAddress(), bitcoinURI);
|
payjoinURIs.put(bitcoinURI.getAddress(), bitcoinURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void clearPayjoinURI(Address address) {
|
||||||
|
payjoinURIs.remove(address);
|
||||||
|
}
|
||||||
|
|
||||||
public static void clearTransactionHistoryCache(Wallet wallet) {
|
public static void clearTransactionHistoryCache(Wallet wallet) {
|
||||||
ElectrumServer.clearRetrievedScriptHashes(wallet);
|
ElectrumServer.clearRetrievedScriptHashes(wallet);
|
||||||
|
|
||||||
|
|
|
@ -206,14 +206,16 @@ public class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
.map(e -> e.getBlockTransaction().getTransaction().getOutputs().get((int)e.getHashIndex().getIndex()))
|
.map(e -> e.getBlockTransaction().getTransaction().getOutputs().get((int)e.getHashIndex().getIndex()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
long changeTotal = ourOutputs.stream().mapToLong(TransactionOutput::getValue).sum();
|
long changeTotal = ourOutputs.stream().mapToLong(TransactionOutput::getValue).sum() - consolidationOutputs.stream().mapToLong(TransactionOutput::getValue).sum();
|
||||||
Transaction tx = blockTransaction.getTransaction();
|
Transaction tx = blockTransaction.getTransaction();
|
||||||
double vSize = tx.getVirtualSize();
|
double vSize = tx.getVirtualSize();
|
||||||
int inputSize = tx.getInputs().get(0).getLength() + (tx.getInputs().get(0).hasWitness() ? tx.getInputs().get(0).getWitness().getLength() / Transaction.WITNESS_SCALE_FACTOR : 0);
|
int inputSize = tx.getInputs().get(0).getLength() + (tx.getInputs().get(0).hasWitness() ? tx.getInputs().get(0).getWitness().getLength() / Transaction.WITNESS_SCALE_FACTOR : 0);
|
||||||
List<BlockTransactionHashIndex> walletUtxos = new ArrayList<>(transactionEntry.getWallet().getWalletUtxos().keySet());
|
List<BlockTransactionHashIndex> walletUtxos = new ArrayList<>(transactionEntry.getWallet().getWalletUtxos().keySet());
|
||||||
|
//Remove any UTXOs created by the transaction that is to be replaced
|
||||||
|
walletUtxos.removeIf(utxo -> ourOutputs.stream().anyMatch(output -> output.getHash().equals(utxo.getHash()) && output.getIndex() == utxo.getIndex()));
|
||||||
Collections.shuffle(walletUtxos);
|
Collections.shuffle(walletUtxos);
|
||||||
while((double)changeTotal / vSize < getMaxFeeRate() && !walletUtxos.isEmpty()) {
|
while((double)changeTotal / vSize < getMaxFeeRate() && !walletUtxos.isEmpty()) {
|
||||||
//If there is insufficent change output, include another random UTXO so the fee can be increased
|
//If there is insufficient change output, include another random UTXO so the fee can be increased
|
||||||
BlockTransactionHashIndex utxo = walletUtxos.remove(0);
|
BlockTransactionHashIndex utxo = walletUtxos.remove(0);
|
||||||
utxos.add(utxo);
|
utxos.add(utxo);
|
||||||
changeTotal += utxo.getValue();
|
changeTotal += utxo.getValue();
|
||||||
|
@ -223,6 +225,7 @@ public class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
List<TransactionOutput> externalOutputs = new ArrayList<>(blockTransaction.getTransaction().getOutputs());
|
List<TransactionOutput> externalOutputs = new ArrayList<>(blockTransaction.getTransaction().getOutputs());
|
||||||
externalOutputs.removeAll(ourOutputs);
|
externalOutputs.removeAll(ourOutputs);
|
||||||
externalOutputs.addAll(consolidationOutputs);
|
externalOutputs.addAll(consolidationOutputs);
|
||||||
|
final long rbfChange = changeTotal;
|
||||||
List<Payment> payments = externalOutputs.stream().map(txOutput -> {
|
List<Payment> payments = externalOutputs.stream().map(txOutput -> {
|
||||||
try {
|
try {
|
||||||
String label = transactionEntry.getLabel() == null ? "" : transactionEntry.getLabel();
|
String label = transactionEntry.getLabel() == null ? "" : transactionEntry.getLabel();
|
||||||
|
@ -240,7 +243,8 @@ public class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(txOutput.getScript().getToAddress() != null) {
|
if(txOutput.getScript().getToAddress() != null) {
|
||||||
return new Payment(txOutput.getScript().getToAddress(), label, txOutput.getValue(), blockTransaction.getTransaction().getOutputs().size() == 1);
|
//Disable change creation by enabling max payment when there is only one output and no additional UTXOs included
|
||||||
|
return new Payment(txOutput.getScript().getToAddress(), label, txOutput.getValue(), blockTransaction.getTransaction().getOutputs().size() == 1 && rbfChange == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -499,6 +499,12 @@ public class PaymentController extends WalletFormController implements Initializ
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
try {
|
||||||
|
AppServices.clearPayjoinURI(getRecipientAddress());
|
||||||
|
} catch(InvalidAddressException e) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
|
||||||
address.setText("");
|
address.setText("");
|
||||||
label.setText("");
|
label.setText("");
|
||||||
|
|
||||||
|
|
|
@ -985,7 +985,8 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
private boolean isMixPossible(List<Payment> payments) {
|
private boolean isMixPossible(List<Payment> payments) {
|
||||||
return (utxoSelectorProperty.get() == null || SorobanServices.canWalletMix(walletForm.getWallet()))
|
return (utxoSelectorProperty.get() == null || SorobanServices.canWalletMix(walletForm.getWallet()))
|
||||||
&& payments.size() == 1
|
&& payments.size() == 1
|
||||||
&& (payments.get(0).getAddress().getScriptType() == getWalletForm().getWallet().getFreshNode(KeyPurpose.RECEIVE).getAddress().getScriptType());
|
&& (payments.get(0).getAddress().getScriptType() == getWalletForm().getWallet().getFreshNode(KeyPurpose.RECEIVE).getAddress().getScriptType())
|
||||||
|
&& AppServices.getPayjoinURI(payments.get(0).getAddress()) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOptimizationButtons(List<Payment> payments) {
|
private void updateOptimizationButtons(List<Payment> payments) {
|
||||||
|
@ -1633,6 +1634,7 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
boolean roundPaymentAmounts = userPayments.stream().anyMatch(payment -> payment.getAmount() % 100 == 0);
|
boolean roundPaymentAmounts = userPayments.stream().anyMatch(payment -> payment.getAmount() % 100 == 0);
|
||||||
boolean mixedAddressTypes = userPayments.stream().anyMatch(payment -> payment.getAddress().getScriptType() != getWalletForm().getWallet().getFreshNode(KeyPurpose.RECEIVE).getAddress().getScriptType());
|
boolean mixedAddressTypes = userPayments.stream().anyMatch(payment -> payment.getAddress().getScriptType() != getWalletForm().getWallet().getFreshNode(KeyPurpose.RECEIVE).getAddress().getScriptType());
|
||||||
boolean addressReuse = userPayments.stream().anyMatch(payment -> walletAddresses.get(payment.getAddress()) != null && !walletAddresses.get(payment.getAddress()).getTransactionOutputs().isEmpty());
|
boolean addressReuse = userPayments.stream().anyMatch(payment -> walletAddresses.get(payment.getAddress()) != null && !walletAddresses.get(payment.getAddress()).getTransactionOutputs().isEmpty());
|
||||||
|
boolean payjoinPresent = userPayments.stream().anyMatch(payment -> AppServices.getPayjoinURI(payment.getAddress()) != null);
|
||||||
|
|
||||||
if(optimizationStrategy == OptimizationStrategy.PRIVACY) {
|
if(optimizationStrategy == OptimizationStrategy.PRIVACY) {
|
||||||
if(payNymPresent) {
|
if(payNymPresent) {
|
||||||
|
@ -1644,6 +1646,8 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
addLabel("Cannot coinjoin due to mixed address types", getInfoGlyph());
|
addLabel("Cannot coinjoin due to mixed address types", getInfoGlyph());
|
||||||
} else if(userPayments.size() > 1) {
|
} else if(userPayments.size() > 1) {
|
||||||
addLabel("Cannot coinjoin due to multiple payments", getInfoGlyph());
|
addLabel("Cannot coinjoin due to multiple payments", getInfoGlyph());
|
||||||
|
} else if(payjoinPresent) {
|
||||||
|
addLabel("Cannot coinjoin due to payjoin", getInfoGlyph());
|
||||||
} else {
|
} else {
|
||||||
if(utxoSelectorProperty().get() != null) {
|
if(utxoSelectorProperty().get() != null) {
|
||||||
addLabel("Cannot fake coinjoin due to coin control", getInfoGlyph());
|
addLabel("Cannot fake coinjoin due to coin control", getInfoGlyph());
|
||||||
|
|
|
@ -162,7 +162,7 @@ public class WhirlpoolServices {
|
||||||
|
|
||||||
public static boolean canWalletMix(Wallet wallet) {
|
public static boolean canWalletMix(Wallet wallet) {
|
||||||
return Whirlpool.WHIRLPOOL_NETWORKS.contains(Network.get())
|
return Whirlpool.WHIRLPOOL_NETWORKS.contains(Network.get())
|
||||||
&& wallet.getScriptType() == ScriptType.P2WPKH
|
&& wallet.getScriptType() != ScriptType.P2TR //Taproot not yet supported
|
||||||
&& wallet.getKeystores().size() == 1
|
&& wallet.getKeystores().size() == 1
|
||||||
&& wallet.getKeystores().get(0).hasSeed()
|
&& wallet.getKeystores().get(0).hasSeed()
|
||||||
&& wallet.getKeystores().get(0).getSeed().getType() == DeterministicSeed.Type.BIP39
|
&& wallet.getKeystores().get(0).getSeed().getType() == DeterministicSeed.Type.BIP39
|
||||||
|
|
Loading…
Reference in a new issue