Add unlock functionality

This commit is contained in:
sqrrm 2018-06-19 20:40:39 +02:00
parent 3ac0d225ef
commit d5d7ea8e7e
No known key found for this signature in database
GPG Key ID: 45235F9EF87089EC
10 changed files with 676 additions and 25 deletions

View File

@ -28,6 +28,7 @@ import bisq.desktop.components.MenuItem;
import bisq.desktop.main.MainView;
import bisq.desktop.main.dao.DaoView;
import bisq.desktop.main.dao.bonding.Lock.LockupBSQView;
import bisq.desktop.main.dao.bonding.unlock.UnlockBSQView;
import bisq.core.locale.Res;
@ -51,6 +52,7 @@ public class BondingView extends ActivatableViewAndModel {
private final Navigation navigation;
private MenuItem lockupBSQ;
private MenuItem unlockBSQ;
private Navigation.Listener listener;
@FXML
@ -80,11 +82,16 @@ public class BondingView extends ActivatableViewAndModel {
final List<Class<? extends View>> baseNavPath = Arrays.asList(MainView.class, DaoView.class, bisq.desktop.main.dao.bonding.BondingView.class);
lockupBSQ = new MenuItem(navigation, toggleGroup, Res.get("dao.bonding.menuItem.lockupBSQ"),
LockupBSQView.class, AwesomeIcon.LIST_UL, baseNavPath);
leftVBox.getChildren().addAll(lockupBSQ);
unlockBSQ = new MenuItem(navigation, toggleGroup, Res.get("dao.bonding.menuItem.unlockBSQ"),
UnlockBSQView.class, AwesomeIcon.LIST_UL, baseNavPath);
leftVBox.getChildren().addAll(lockupBSQ, unlockBSQ);
}
@Override
protected void activate() {
lockupBSQ.activate();
unlockBSQ.activate();
navigation.addListener(listener);
ViewPath viewPath = navigation.getCurrentPath();
if (viewPath.size() == 3 && viewPath.indexOf(BondingView.class) == 2 ||
@ -105,6 +112,7 @@ public class BondingView extends ActivatableViewAndModel {
navigation.removeListener(listener);
lockupBSQ.deactivate();
unlockBSQ.deactivate();
}
private void loadView(Class<? extends View> viewClass) {
@ -112,9 +120,6 @@ public class BondingView extends ActivatableViewAndModel {
content.getChildren().setAll(view.getRoot());
if (view instanceof LockupBSQView) lockupBSQ.setSelected(true);
}
public Class<? extends View> getSelectedViewClass() {
return selectedViewClass;
else if (view instanceof UnlockBSQView) unlockBSQ.setSelected(true);
}
}

View File

@ -37,23 +37,17 @@ import bisq.core.btc.Restrictions;
import bisq.core.btc.wallet.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.TxBroadcastException;
import bisq.core.btc.wallet.TxBroadcastTimeoutException;
import bisq.core.btc.wallet.TxBroadcaster;
import bisq.core.btc.wallet.TxMalleabilityException;
import bisq.core.btc.wallet.WalletsManager;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.voting.proposal.param.Param;
import bisq.core.locale.Res;
import bisq.core.util.CoinUtil;
import bisq.network.p2p.P2PService;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import javax.inject.Inject;
@ -131,14 +125,14 @@ public class LockupBSQView extends ActivatableView<GridPane, Void> implements Bs
focusOutListener = (observable, oldValue, newValue) -> {
if (!newValue)
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
};
lockupButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.bonding.lock.lockupButton"));
lockupButton.setOnAction((event) -> {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
Address lockupAddress = bsqWalletService.getUnusedAddress();
Coin lockupAmount = bsqFormatter.parseToCoin(amountInputTextField.getText());
int lockupTime = Integer.parseInt(timeInputTextField.getText());
try {
@ -187,7 +181,8 @@ public class LockupBSQView extends ActivatableView<GridPane, Void> implements Bs
amountInputTextField.focusedProperty().addListener(focusOutListener);
bsqWalletService.addBsqBalanceListener(this);
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
}
@Override
@ -201,7 +196,8 @@ public class LockupBSQView extends ActivatableView<GridPane, Void> implements Bs
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
Coin lockedForVotingBalance,
Coin lockedInBondsBalance) {
Coin lockedInBondsBalance,
Coin unlockingBondsBalance) {
bsqValidator.setAvailableBalance(confirmedBalance);
boolean isValid = bsqValidator.validate(amountInputTextField.getText()).isValid;
lockupButton.setDisable(!isValid);

View File

@ -0,0 +1,142 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.main.dao.bonding.unlock;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.indicator.TxConfidenceIndicator;
import bisq.desktop.util.BsqFormatter;
import bisq.desktop.util.GUIUtil;
import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.state.StateService;
import bisq.core.dao.state.blockchain.TxType;
import bisq.core.locale.Res;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import javafx.scene.control.Tooltip;
import java.util.Date;
import java.util.Optional;
import lombok.Data;
import static com.google.common.base.Preconditions.checkNotNull;
@Data
class LockedBsqTxListItem {
private final Transaction transaction;
private final BsqWalletService bsqWalletService;
private final BtcWalletService btcWalletService;
private final DaoFacade daoFacade;
private final StateService stateService;
private final BsqFormatter bsqFormatter;
private final Date date;
private final String txId;
private int confirmations = 0;
private Coin amount;
private int lockTime;
private AutoTooltipButton button;
private TxConfidenceIndicator txConfidenceIndicator;
private TxConfidenceListener txConfidenceListener;
private boolean issuanceTx;
LockedBsqTxListItem(Transaction transaction,
BsqWalletService bsqWalletService,
BtcWalletService btcWalletService,
DaoFacade daoFacade,
StateService stateService,
Date date,
BsqFormatter bsqFormatter) {
this.transaction = transaction;
this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService;
this.daoFacade = daoFacade;
this.stateService = stateService;
this.date = date;
this.bsqFormatter = bsqFormatter;
txId = transaction.getHashAsString();
setupConfidence(bsqWalletService);
checkNotNull(transaction, "transaction must not be null as we only have list items from transactions " +
"which are available in the wallet");
amount = bsqWalletService.getValueLockedUpInBond(transaction);
Optional<Integer> opLockTime = stateService.getLockTime(transaction.getHashAsString());
lockTime = opLockTime.isPresent() ? opLockTime.get() : -1;
button = new AutoTooltipButton();
button.setMinWidth(70);
button.setText(Res.get("dao.bonding.unlock.unlock"));
button.setVisible(true);
button.setManaged(true);
}
private void setupConfidence(BsqWalletService bsqWalletService) {
txConfidenceIndicator = new TxConfidenceIndicator();
txConfidenceIndicator.setId("funds-confidence");
Tooltip tooltip = new Tooltip();
txConfidenceIndicator.setProgress(0);
txConfidenceIndicator.setPrefSize(24, 24);
txConfidenceIndicator.setTooltip(tooltip);
txConfidenceListener = new TxConfidenceListener(txId) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence, tooltip);
}
};
bsqWalletService.addTxConfidenceListener(txConfidenceListener);
updateConfidence(bsqWalletService.getConfidenceForTxId(txId), tooltip);
}
private void updateConfidence(TransactionConfidence confidence, Tooltip tooltip) {
if (confidence != null) {
GUIUtil.updateConfidence(confidence, tooltip, txConfidenceIndicator);
confirmations = confidence.getDepthInBlocks();
}
}
public boolean isLocked() {
return getTxType() == TxType.LOCK_UP;
}
public void cleanup() {
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
}
public TxType getTxType() {
return daoFacade.getTx(txId)
.flatMap(tx -> daoFacade.getTxType(tx.getId()))
.orElse(confirmations == 0 ? TxType.UNVERIFIED : TxType.UNDEFINED_TX_TYPE);
}
public void setAmount(Coin amount) {
this.amount = amount;
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ This file is part of Bisq.
~
~ Bisq is free software: you can redistribute it and/or modify it
~ under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or (at
~ your option) any later version.
~
~ Bisq is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
~ License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with Bisq. If not, see <http://www.gnu.org/licenses/>.
-->
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.bonding.unlock.UnlockBSQView"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0.0"
xmlns:fx="http://javafx.com/fxml">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="160.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
</columnConstraints>
</GridPane>

View File

@ -0,0 +1,462 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.main.dao.bonding.unlock;
import bisq.desktop.Navigation;
import bisq.desktop.common.view.ActivatableView;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.main.MainView;
import bisq.desktop.main.dao.wallet.BsqBalanceUtil;
import bisq.desktop.main.funds.FundsView;
import bisq.desktop.main.funds.deposit.DepositView;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.BsqFormatter;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.validation.BsqValidator;
import bisq.core.btc.wallet.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.state.BlockListener;
import bisq.core.dao.state.StateService;
import bisq.core.dao.state.blockchain.Block;
import bisq.core.dao.state.blockchain.Tx;
import bisq.core.dao.state.blockchain.TxOutput;
import bisq.core.dao.state.blockchain.TxType;
import bisq.core.locale.Res;
import bisq.core.user.Preferences;
import bisq.network.p2p.P2PService;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import javax.inject.Inject;
import de.jensd.fx.fontawesome.AwesomeIcon;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.geometry.Insets;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.util.Callback;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@FxmlView
public class UnlockBSQView extends ActivatableView<GridPane, Void> implements BsqBalanceListener, BlockListener {
private TableView<LockedBsqTxListItem> tableView;
private Pane rootParent;
private final BsqWalletService bsqWalletService;
private final BtcWalletService btcWalletService;
private final BsqFormatter bsqFormatter;
private final BsqBalanceUtil bsqBalanceUtil;
private final BsqValidator bsqValidator;
private final DaoFacade daoFacade;
private final Preferences preferences;
private final StateService stateService;
private final WalletsSetup walletsSetup;
private final P2PService p2PService;
private final Navigation navigation;
private int gridRow = 0;
private boolean synched;
private LockedBsqTxListItem selectedItem;
private final ObservableList<LockedBsqTxListItem> observableList = FXCollections.observableArrayList();
private final FilteredList<LockedBsqTxListItem> lockedTxs = new FilteredList<>(observableList);
private ListChangeListener<Transaction> walletBsqTransactionsListener;
private ChangeListener<Number> walletChainHeightListener;
private final DoubleProperty initialOccupiedHeight = new SimpleDoubleProperty(-1);
private ChangeListener<Number> parentHeightListener;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private UnlockBSQView(BsqWalletService bsqWalletService,
BtcWalletService btcWalletService,
BsqFormatter bsqFormatter,
BsqBalanceUtil bsqBalanceUtil,
BsqValidator bsqValidator,
DaoFacade daoFacade,
Preferences preferences,
StateService stateService,
WalletsSetup walletsSetup,
P2PService p2PService,
Navigation navigation) {
this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService;
this.bsqFormatter = bsqFormatter;
this.bsqBalanceUtil = bsqBalanceUtil;
this.bsqValidator = bsqValidator;
this.daoFacade = daoFacade;
this.preferences = preferences;
this.stateService = stateService;
this.walletsSetup = walletsSetup;
this.p2PService = p2PService;
this.navigation = navigation;
}
@Override
public void initialize() {
// TODO: Show balance locked up in bonds
gridRow = bsqBalanceUtil.addGroup(root, gridRow);
tableView = new TableView<>();
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
addTxIdColumn();
addAmountColumn();
addLockTimeColumn();
addUnlockColumn();
lockedTxs.setPredicate(item -> item.isLocked());
walletBsqTransactionsListener = change -> updateList();
walletChainHeightListener = (observable, oldValue, newValue) -> onUpdateAnyChainHeight();
parentHeightListener = (observable, oldValue, newValue) -> layout();
VBox vBox = new VBox();
vBox.setSpacing(10);
GridPane.setRowIndex(vBox, ++gridRow);
GridPane.setColumnSpan(vBox, 2);
GridPane.setMargin(vBox, new Insets(40, -10, 5, -10));
vBox.getChildren().addAll(tableView);
root.getChildren().add(vBox);
}
private void addTxIdColumn() {
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> column = new AutoTooltipTableColumn<>(Res.get("shared.txId"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60);
column.setCellFactory(
new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>, TableCell<LockedBsqTxListItem,
LockedBsqTxListItem>>() {
@Override
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
LockedBsqTxListItem> column) {
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
private HyperlinkWithIcon hyperlinkWithIcon;
@Override
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
String transactionId = item.getTxId();
hyperlinkWithIcon = new HyperlinkWithIcon(transactionId, AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setOnAction(event -> openTxInBlockExplorer(item));
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", transactionId)));
setGraphic(hyperlinkWithIcon);
} else {
setGraphic(null);
if (hyperlinkWithIcon != null)
hyperlinkWithIcon.setOnAction(null);
}
}
};
}
});
tableView.getColumns().add(column);
}
private void addAmountColumn() {
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> column =
new AutoTooltipTableColumn<>(Res.get("shared.amountWithCur", "BSQ"));
column.setMinWidth(120);
column.setMaxWidth(column.getMinWidth());
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>,
TableCell<LockedBsqTxListItem, LockedBsqTxListItem>>() {
@Override
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
LockedBsqTxListItem> column) {
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
@Override
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
TxType txType = item.getTxType();
setText(item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal() ?
bsqFormatter.formatCoin(item.getAmount()) :
Res.get("shared.na"));
} else
setText("");
}
};
}
});
tableView.getColumns().add(column);
}
private void addLockTimeColumn() {
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> column =
new AutoTooltipTableColumn<>(Res.get("dao.bonding.unlock.time"));
column.setMinWidth(120);
column.setMaxWidth(column.getMinWidth());
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>,
TableCell<LockedBsqTxListItem, LockedBsqTxListItem>>() {
@Override
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
LockedBsqTxListItem> column) {
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
@Override
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
TxType txType = item.getTxType();
setText(item.getConfirmations() > 0 && txType.ordinal() > TxType.INVALID.ordinal() ?
Integer.toString(item.getLockTime()) :
Res.get("shared.na"));
} else
setText("");
}
};
}
});
tableView.getColumns().add(column);
}
private void addUnlockColumn() {
TableColumn<LockedBsqTxListItem, LockedBsqTxListItem> unlockColumn = new TableColumn<>();
unlockColumn.setMinWidth(130);
unlockColumn.setMaxWidth(unlockColumn.getMinWidth());
unlockColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
unlockColumn.setCellFactory(new Callback<TableColumn<LockedBsqTxListItem, LockedBsqTxListItem>,
TableCell<LockedBsqTxListItem, LockedBsqTxListItem>>() {
@Override
public TableCell<LockedBsqTxListItem, LockedBsqTxListItem> call(TableColumn<LockedBsqTxListItem,
LockedBsqTxListItem> column) {
return new TableCell<LockedBsqTxListItem, LockedBsqTxListItem>() {
Button button;
@Override
public void updateItem(final LockedBsqTxListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
if (button == null) {
button = item.getButton();
button.setOnAction(e -> {
UnlockBSQView.this.selectedItem = item;
UnlockBSQView.this.onButtonClick();
});
setGraphic(button);
}
} else {
setGraphic(null);
if (button != null) {
button.setOnAction(null);
button = null;
}
}
}
};
}
});
unlockColumn.setComparator(Comparator.comparing(LockedBsqTxListItem::getConfirmations));
tableView.getColumns().add(unlockColumn);
}
private void onButtonClick() {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
Optional<TxOutput> lockedTxOutput = stateService.getLockedTxOutput(selectedItem.getTxId());
if (!lockedTxOutput.isPresent()) {
log.warn("Locked output not found, txId = ", selectedItem.getTxId());
return;
}
Coin unlockAmount = Coin.valueOf(lockedTxOutput.get().getValue());
Optional<Integer> opLockTime = stateService.getLockTime(lockedTxOutput.get());
int lockTime = opLockTime.isPresent() ? opLockTime.get() : -1;
try {
new Popup<>().headLine(Res.get("dao.bonding.unlock.sendTx.headline"))
.confirmation(Res.get("dao.bonding.unlock.sendTx.details",
bsqFormatter.formatCoinWithCode(unlockAmount),
lockTime
))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> {
daoFacade.publishUnlockTx(selectedItem.getTxId(),
() -> {
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
},
errorMessage -> new Popup<>().warning(errorMessage.toString()).show()
);
})
.closeButtonText(Res.get("shared.cancel"))
.show();
} catch (Throwable t) {
if (t instanceof InsufficientMoneyException) {
final Coin missingCoin = ((InsufficientMoneyException) t).missing;
final String missing = missingCoin != null ? missingCoin.toFriendlyString() : "null";
//noinspection unchecked
new Popup<>().warning(Res.get("popup.warning.insufficientBtcFundsForBsqTx", missing))
.actionButtonTextWithGoTo("navigation.funds.depositFunds")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
.show();
} else {
log.error(t.toString());
t.printStackTrace();
new Popup<>().warning(t.getMessage()).show();
}
}
} else {
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
}
log.info("unlock tx: {}", selectedItem.getTxId());
}
private void openTxInBlockExplorer(LockedBsqTxListItem item) {
if (item.getTxId() != null)
GUIUtil.openWebPage(preferences.getBsqBlockChainExplorer().txUrl + item.getTxId());
}
@Override
protected void activate() {
bsqBalanceUtil.activate();
bsqWalletService.addBsqBalanceListener(this);
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
bsqWalletService.getWalletTransactions().addListener(walletBsqTransactionsListener);
bsqWalletService.addBsqBalanceListener(this);
btcWalletService.getChainHeightProperty().addListener(walletChainHeightListener);
tableView.setItems(lockedTxs);
daoFacade.addBlockListener(this);
if (root.getParent() instanceof Pane) {
rootParent = (Pane) root.getParent();
rootParent.heightProperty().addListener(parentHeightListener);
}
updateList();
onUpdateAnyChainHeight();
layout();
}
@Override
public void onBlockAdded(Block block) {
onUpdateAnyChainHeight();
}
private void onUpdateAnyChainHeight() {
final int bsqBlockChainHeight = daoFacade.getChainHeight();
final int bsqWalletChainHeight = bsqWalletService.getBestChainHeight();
if (bsqWalletChainHeight > 0) {
synched = bsqWalletChainHeight == bsqBlockChainHeight;
}
updateList();
}
private void updateList() {
observableList.forEach(LockedBsqTxListItem::cleanup);
// copy list to avoid ConcurrentModificationException
final List<Transaction> walletTransactions = new ArrayList<>(bsqWalletService.getWalletTransactions());
List<LockedBsqTxListItem> items = walletTransactions.stream()
.map(transaction -> {
return new LockedBsqTxListItem(transaction,
bsqWalletService,
btcWalletService,
daoFacade,
stateService,
transaction.getUpdateTime(),
bsqFormatter);
})
.collect(Collectors.toList());
observableList.setAll(items);
}
private void layout() {
GUIUtil.fillAvailableHeight(root, tableView, initialOccupiedHeight);
}
@Override
protected void deactivate() {
bsqBalanceUtil.deactivate();
bsqWalletService.removeBsqBalanceListener(this);
bsqBalanceUtil.deactivate();
lockedTxs.predicateProperty().unbind();
bsqWalletService.getWalletTransactions().removeListener(walletBsqTransactionsListener);
bsqWalletService.removeBsqBalanceListener(this);
btcWalletService.getChainHeightProperty().removeListener(walletChainHeightListener);
daoFacade.removeBlockListener(this);
observableList.forEach(LockedBsqTxListItem::cleanup);
if (rootParent != null)
rootParent.heightProperty().removeListener(parentHeightListener);
}
@Override
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
Coin lockedForVotingBalance,
Coin lockedInBondsBalance,
Coin unlockingBondsBalance) {
bsqValidator.setAvailableBalance(confirmedBalance);
}
}

View File

@ -114,7 +114,8 @@ public class ActiveBallotsView extends BaseProposalView implements BsqBalanceLis
onUpdateBalances(bsqWalletService.getAvailableBalance(),
bsqWalletService.getPendingBalance(),
bsqWalletService.getLockedForVotingBalance(),
bsqWalletService.getLockedInBondsBalance());
bsqWalletService.getLockedInBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
voteButton.setOnAction(e -> onVote());
@ -141,7 +142,8 @@ public class ActiveBallotsView extends BaseProposalView implements BsqBalanceLis
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
Coin lockedForVotingBalance,
Coin lockedInBondsBalance) {
Coin lockedInBondsBalance,
Coin unlockingBondsBalance) {
stakeInputTextField.setPromptText(Res.get("dao.proposal.myVote.stake.prompt",
bsqFormatter.formatCoinWithCode(confirmedBalance)));
}

View File

@ -83,7 +83,8 @@ public class BsqBalanceUtil implements BsqBalanceListener {
onUpdateBalances(bsqWalletService.getAvailableBalance(),
bsqWalletService.getPendingBalance(),
bsqWalletService.getLockedForVotingBalance(),
bsqWalletService.getLockedInBondsBalance());
bsqWalletService.getLockedInBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
bsqWalletService.addBsqBalanceListener(this);
}
@ -96,11 +97,16 @@ public class BsqBalanceUtil implements BsqBalanceListener {
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
Coin lockedForVotingBalance,
Coin lockedInBondsBalance) {
Coin lockedInBondsBalance,
Coin unlockingBondsBalance) {
confirmedBalanceTextField.setText(bsqFormatter.formatCoinWithCode(confirmedBalance));
pendingBalanceTextField.setText(bsqFormatter.formatCoinWithCode(pendingBalance));
lockedForVoteBalanceTextField.setText(bsqFormatter.formatCoinWithCode(lockedForVotingBalance));
final Coin total = confirmedBalance.add(pendingBalance).add(lockedForVotingBalance).add(lockedInBondsBalance);
final Coin total = confirmedBalance
.add(pendingBalance)
.add(lockedForVotingBalance)
.add(lockedInBondsBalance)
.add(unlockingBondsBalance);
totalBalanceTextField.setText(bsqFormatter.formatCoinWithCode(total));
}
}

View File

@ -131,7 +131,8 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
focusOutListener = (observable, oldValue, newValue) -> {
if (!newValue)
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
};
sendButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.wallet.send.send"));
@ -215,7 +216,8 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
amountInputTextField.focusedProperty().addListener(focusOutListener);
bsqWalletService.addBsqBalanceListener(this);
onUpdateBalances(bsqWalletService.getAvailableBalance(), bsqWalletService.getPendingBalance(),
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance());
bsqWalletService.getLockedForVotingBalance(), bsqWalletService.getLockedInBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
}
@Override
@ -230,7 +232,8 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
Coin lockedForVotingBalance,
Coin lockedInBondsBalance) {
Coin lockedInBondsBalance,
Coin unlockingBondsBalance) {
bsqValidator.setAvailableBalance(confirmedBalance);
boolean isValid = bsqAddressValidator.validate(receiversAddressInputTextField.getText()).isValid &&
bsqValidator.validate(amountInputTextField.getText()).isValid;

View File

@ -208,7 +208,8 @@ public class BsqTxView extends ActivatableView<GridPane, Void> implements BsqBal
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
Coin lockedForVotingBalance,
Coin lockedInBondsBalance) {
Coin lockedInBondsBalance,
Coin unlockingBondsBalance) {
updateList();
}

View File

@ -539,7 +539,8 @@ public abstract class EditableOfferDataModel extends OfferDataModel implements B
public void onUpdateBalances(Coin confirmedBalance,
Coin pendingBalance,
Coin lockedForVotingBalance,
Coin lockedInBondsBalance) {
Coin lockedInBondsBalance,
Coin unlockingBondsBalance) {
updateBalance();
}