mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
freeze and unfreeze utxos
This commit is contained in:
parent
88dfde3c67
commit
572e451279
8 changed files with 119 additions and 23 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit 6b20c6558ab7cef6f582461692232a7687fe26c8
|
Subproject commit deb45687c08d4ff824ab7559233249c345d9c86a
|
|
@ -2,7 +2,6 @@ package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.Utils;
|
import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.drongo.address.Address;
|
import com.sparrowwallet.drongo.address.Address;
|
||||||
import com.sparrowwallet.drongo.protocol.NonStandardScriptException;
|
|
||||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||||
import com.sparrowwallet.drongo.protocol.TransactionOutput;
|
import com.sparrowwallet.drongo.protocol.TransactionOutput;
|
||||||
import com.sparrowwallet.drongo.wallet.*;
|
import com.sparrowwallet.drongo.wallet.*;
|
||||||
|
@ -125,7 +124,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
} else if(entry instanceof HashIndexEntry) {
|
} else if(entry instanceof HashIndexEntry) {
|
||||||
HashIndexEntry hashIndexEntry = (HashIndexEntry)entry;
|
HashIndexEntry hashIndexEntry = (HashIndexEntry)entry;
|
||||||
setText(hashIndexEntry.getDescription());
|
setText(hashIndexEntry.getDescription());
|
||||||
setContextMenu(new HashIndexEntryContextMenu(hashIndexEntry));
|
setContextMenu(new HashIndexEntryContextMenu(getTreeTableView(), hashIndexEntry));
|
||||||
Tooltip tooltip = new Tooltip();
|
Tooltip tooltip = new Tooltip();
|
||||||
tooltip.setText(hashIndexEntry.getHashIndex().toString());
|
tooltip.setText(hashIndexEntry.getHashIndex().toString());
|
||||||
setTooltip(tooltip);
|
setTooltip(tooltip);
|
||||||
|
@ -140,26 +139,13 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
});
|
});
|
||||||
actionBox.getChildren().add(viewTransactionButton);
|
actionBox.getChildren().add(viewTransactionButton);
|
||||||
|
|
||||||
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && hashIndexEntry.isSpendable()) {
|
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && hashIndexEntry.isSpendable() && !hashIndexEntry.getHashIndex().isSpent()) {
|
||||||
Button spendUtxoButton = new Button("");
|
Button spendUtxoButton = new Button("");
|
||||||
Glyph sendGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.SEND);
|
Glyph sendGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.SEND);
|
||||||
sendGlyph.setFontSize(12);
|
sendGlyph.setFontSize(12);
|
||||||
spendUtxoButton.setGraphic(sendGlyph);
|
spendUtxoButton.setGraphic(sendGlyph);
|
||||||
spendUtxoButton.setOnAction(event -> {
|
spendUtxoButton.setOnAction(event -> {
|
||||||
List<HashIndexEntry> utxoEntries = getTreeTableView().getSelectionModel().getSelectedCells().stream()
|
sendSelectedUtxos(getTreeTableView(), hashIndexEntry);
|
||||||
.map(tp -> tp.getTreeItem().getValue())
|
|
||||||
.filter(e -> e instanceof HashIndexEntry)
|
|
||||||
.map(e -> (HashIndexEntry)e)
|
|
||||||
.filter(e -> e.getType().equals(HashIndexEntry.Type.OUTPUT) && e.isSpendable())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
if(!utxoEntries.contains(hashIndexEntry)) {
|
|
||||||
utxoEntries = List.of(hashIndexEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<BlockTransactionHashIndex> spendingUtxos = utxoEntries.stream().map(HashIndexEntry::getHashIndex).collect(Collectors.toList());
|
|
||||||
EventManager.get().post(new SendActionEvent(hashIndexEntry.getWallet(), spendingUtxos));
|
|
||||||
Platform.runLater(() -> EventManager.get().post(new SpendUtxoEvent(hashIndexEntry.getWallet(), spendingUtxos)));
|
|
||||||
});
|
});
|
||||||
actionBox.getChildren().add(spendUtxoButton);
|
actionBox.getChildren().add(spendUtxoButton);
|
||||||
}
|
}
|
||||||
|
@ -223,6 +209,33 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
return AppController.getTargetBlockFeeRates().values().iterator().next();
|
return AppController.getTargetBlockFeeRates().values().iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void sendSelectedUtxos(TreeTableView<Entry> treeTableView, HashIndexEntry hashIndexEntry) {
|
||||||
|
List<HashIndexEntry> utxoEntries = treeTableView.getSelectionModel().getSelectedCells().stream()
|
||||||
|
.map(tp -> tp.getTreeItem().getValue())
|
||||||
|
.filter(e -> e instanceof HashIndexEntry)
|
||||||
|
.map(e -> (HashIndexEntry)e)
|
||||||
|
.filter(e -> e.getType().equals(HashIndexEntry.Type.OUTPUT) && e.isSpendable())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if(!utxoEntries.contains(hashIndexEntry)) {
|
||||||
|
utxoEntries = List.of(hashIndexEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<BlockTransactionHashIndex> spendingUtxos = utxoEntries.stream().map(HashIndexEntry::getHashIndex).collect(Collectors.toList());
|
||||||
|
EventManager.get().post(new SendActionEvent(hashIndexEntry.getWallet(), spendingUtxos));
|
||||||
|
Platform.runLater(() -> EventManager.get().post(new SpendUtxoEvent(hashIndexEntry.getWallet(), spendingUtxos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void freezeUtxo(HashIndexEntry hashIndexEntry) {
|
||||||
|
hashIndexEntry.getHashIndex().setStatus(Status.FROZEN);
|
||||||
|
EventManager.get().post(new WalletUtxoStatusChangedEvent(hashIndexEntry.getWallet(), hashIndexEntry.getHashIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void unfreezeUtxo(HashIndexEntry hashIndexEntry) {
|
||||||
|
hashIndexEntry.getHashIndex().setStatus(null);
|
||||||
|
EventManager.get().post(new WalletUtxoStatusChangedEvent(hashIndexEntry.getWallet(), hashIndexEntry.getHashIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
private static class UnconfirmedTransactionContextMenu extends ContextMenu {
|
private static class UnconfirmedTransactionContextMenu extends ContextMenu {
|
||||||
public UnconfirmedTransactionContextMenu(TransactionEntry transactionEntry) {
|
public UnconfirmedTransactionContextMenu(TransactionEntry transactionEntry) {
|
||||||
BlockTransaction blockTransaction = transactionEntry.getBlockTransaction();
|
BlockTransaction blockTransaction = transactionEntry.getBlockTransaction();
|
||||||
|
@ -320,7 +333,7 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class HashIndexEntryContextMenu extends ContextMenu {
|
private static class HashIndexEntryContextMenu extends ContextMenu {
|
||||||
public HashIndexEntryContextMenu(HashIndexEntry hashIndexEntry) {
|
public HashIndexEntryContextMenu(TreeTableView<Entry> treeTableView, HashIndexEntry hashIndexEntry) {
|
||||||
String label = "Copy " + (hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) ? "Transaction Output" : "Transaction Input");
|
String label = "Copy " + (hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) ? "Transaction Output" : "Transaction Input");
|
||||||
MenuItem copyHashIndex = new MenuItem(label);
|
MenuItem copyHashIndex = new MenuItem(label);
|
||||||
copyHashIndex.setOnAction(AE -> {
|
copyHashIndex.setOnAction(AE -> {
|
||||||
|
@ -329,8 +342,34 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
|
||||||
content.putString(hashIndexEntry.getHashIndex().toString());
|
content.putString(hashIndexEntry.getHashIndex().toString());
|
||||||
Clipboard.getSystemClipboard().setContent(content);
|
Clipboard.getSystemClipboard().setContent(content);
|
||||||
});
|
});
|
||||||
|
|
||||||
getItems().add(copyHashIndex);
|
getItems().add(copyHashIndex);
|
||||||
|
|
||||||
|
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && hashIndexEntry.isSpendable() && !hashIndexEntry.getHashIndex().isSpent()) {
|
||||||
|
MenuItem sendSelected = new MenuItem("Send Selected");
|
||||||
|
sendSelected.setOnAction(AE -> {
|
||||||
|
hide();
|
||||||
|
sendSelectedUtxos(treeTableView, hashIndexEntry);
|
||||||
|
});
|
||||||
|
getItems().add(sendSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hashIndexEntry.getType().equals(HashIndexEntry.Type.OUTPUT) && !hashIndexEntry.getHashIndex().isSpent()) {
|
||||||
|
if(hashIndexEntry.getHashIndex().getStatus() == null || hashIndexEntry.getHashIndex().getStatus() != Status.FROZEN) {
|
||||||
|
MenuItem freezeUtxo = new MenuItem("Freeze UTXO");
|
||||||
|
freezeUtxo.setOnAction(AE -> {
|
||||||
|
hide();
|
||||||
|
freezeUtxo(hashIndexEntry);
|
||||||
|
});
|
||||||
|
getItems().add(freezeUtxo);
|
||||||
|
} else {
|
||||||
|
MenuItem unfreezeUtxo = new MenuItem("Unfreeze UTXO");
|
||||||
|
unfreezeUtxo.setOnAction(AE -> {
|
||||||
|
hide();
|
||||||
|
unfreezeUtxo(hashIndexEntry);
|
||||||
|
});
|
||||||
|
getItems().add(unfreezeUtxo);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.sparrowwallet.sparrow.event;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
|
||||||
|
public class WalletUtxoStatusChangedEvent extends WalletDataChangedEvent {
|
||||||
|
private final BlockTransactionHashIndex utxo;
|
||||||
|
|
||||||
|
public WalletUtxoStatusChangedEvent(Wallet wallet, BlockTransactionHashIndex utxo) {
|
||||||
|
super(wallet);
|
||||||
|
this.utxo = utxo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockTransactionHashIndex getUtxo() {
|
||||||
|
return utxo;
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,4 +67,12 @@ public class AddressesController extends WalletFormController implements Initial
|
||||||
receiveTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
|
receiveTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
|
||||||
changeTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
|
changeTable.setBitcoinUnit(getWalletForm().getWallet(), event.getBitcoinUnit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
|
||||||
|
if(event.getWallet().equals(getWalletForm().getWallet())) {
|
||||||
|
receiveTable.refresh();
|
||||||
|
changeTable.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.wallet;
|
||||||
import com.sparrowwallet.drongo.KeyPurpose;
|
import com.sparrowwallet.drongo.KeyPurpose;
|
||||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
||||||
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Status;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.control.DateLabel;
|
import com.sparrowwallet.sparrow.control.DateLabel;
|
||||||
|
@ -57,7 +58,7 @@ public class HashIndexEntry extends Entry implements Comparable<HashIndexEntry>
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSpendable() {
|
public boolean isSpendable() {
|
||||||
return !isSpent() && (hashIndex.getHeight() > 0 || getWallet().allInputsFromWallet(hashIndex.getHash()));
|
return !isSpent() && (hashIndex.getHeight() > 0 || getWallet().allInputsFromWallet(hashIndex.getHash())) && (hashIndex.getStatus() == null || hashIndex.getStatus() != Status.FROZEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -485,10 +485,10 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
private List<UtxoFilter> getUtxoFilters() {
|
private List<UtxoFilter> getUtxoFilters() {
|
||||||
UtxoFilter utxoFilter = utxoFilterProperty.get();
|
UtxoFilter utxoFilter = utxoFilterProperty.get();
|
||||||
if(utxoFilter != null) {
|
if(utxoFilter != null) {
|
||||||
return List.of(utxoFilter);
|
return List.of(utxoFilter, new FrozenUtxoFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.emptyList();
|
return List.of(new FrozenUtxoFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFeeRateSelection(FeeRatesSelection feeRatesSelection) {
|
private void updateFeeRateSelection(FeeRatesSelection feeRatesSelection) {
|
||||||
|
@ -877,4 +877,21 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
|
||||||
|
if(event.getWallet().equals(getWalletForm().getWallet())) {
|
||||||
|
UtxoSelector utxoSelector = utxoSelectorProperty.get();
|
||||||
|
if(utxoSelector instanceof MaxUtxoSelector) {
|
||||||
|
updateTransaction(true);
|
||||||
|
} else if(utxoSelectorProperty().get() instanceof PresetUtxoSelector) {
|
||||||
|
PresetUtxoSelector presetUtxoSelector = new PresetUtxoSelector(((PresetUtxoSelector)utxoSelector).getPresetUtxos());
|
||||||
|
presetUtxoSelector.getPresetUtxos().remove(event.getUtxo());
|
||||||
|
utxoSelectorProperty.set(presetUtxoSelector);
|
||||||
|
updateTransaction(true);
|
||||||
|
} else {
|
||||||
|
updateTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,4 +127,11 @@ public class TransactionsController extends WalletFormController implements Init
|
||||||
public void walletHistoryStatus(WalletHistoryStatusEvent event) {
|
public void walletHistoryStatus(WalletHistoryStatusEvent event) {
|
||||||
transactionsTable.updateHistoryStatus(event);
|
transactionsTable.updateHistoryStatus(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
|
||||||
|
if(event.getWallet().equals(getWalletForm().getWallet())) {
|
||||||
|
transactionsTable.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,4 +132,11 @@ public class UtxosController extends WalletFormController implements Initializab
|
||||||
public void walletHistoryStatus(WalletHistoryStatusEvent event) {
|
public void walletHistoryStatus(WalletHistoryStatusEvent event) {
|
||||||
utxosTable.updateHistoryStatus(event);
|
utxosTable.updateHistoryStatus(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletUtxoStatusChanged(WalletUtxoStatusChangedEvent event) {
|
||||||
|
if(event.getWallet().equals(getWalletForm().getWallet())) {
|
||||||
|
utxosTable.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue