diff --git a/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java b/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java index 371fe77ba31..3658f3e8e7f 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/BaseProposalView.java @@ -23,12 +23,14 @@ import bisq.desktop.components.AutoTooltipTableColumn; import bisq.desktop.components.HyperlinkWithIcon; import bisq.desktop.components.TableGroupHeadline; +import bisq.desktop.util.BSFormatter; import bisq.desktop.util.BsqFormatter; import bisq.core.btc.wallet.BsqWalletService; import bisq.core.dao.blockchain.BsqBlockChain; import bisq.core.dao.blockchain.ReadableBsqBlockChain; import bisq.core.dao.blockchain.vo.BsqBlock; +import bisq.core.dao.param.DaoParamService; import bisq.core.dao.vote.PeriodService; import bisq.core.dao.vote.proposal.Proposal; import bisq.core.dao.vote.proposal.ProposalPayload; @@ -73,8 +75,10 @@ public abstract class BaseProposalView extends ActivatableView i protected final ProposalService proposalService; protected final ReadableBsqBlockChain readableBsqBlockChain; + protected final DaoParamService daoParamService; protected final BsqWalletService bsqWalletService; protected final BsqFormatter bsqFormatter; + protected final BSFormatter btcFormatter; protected final ObservableList proposalListItems = FXCollections.observableArrayList(); protected final SortedList sortedList = new SortedList<>(proposalListItems); @@ -101,13 +105,17 @@ public abstract class BaseProposalView extends ActivatableView i protected BaseProposalView(ProposalService proposalService, BsqWalletService bsqWalletService, ReadableBsqBlockChain readableBsqBlockChain, + DaoParamService daoParamService, PeriodService periodService, - BsqFormatter bsqFormatter) { + BsqFormatter bsqFormatter, + BSFormatter btcFormatter) { this.proposalService = proposalService; this.bsqWalletService = bsqWalletService; this.readableBsqBlockChain = readableBsqBlockChain; + this.daoParamService = daoParamService; this.periodService = periodService; this.bsqFormatter = bsqFormatter; + this.btcFormatter = btcFormatter; } @Override diff --git a/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java b/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java index 99903701125..330dbd98407 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/ProposalListItem.java @@ -27,11 +27,11 @@ import bisq.core.dao.blockchain.ReadableBsqBlockChain; import bisq.core.dao.blockchain.vo.BsqBlock; import bisq.core.dao.blockchain.vo.Tx; +import bisq.core.dao.vote.BooleanVote; import bisq.core.dao.vote.PeriodService; +import bisq.core.dao.vote.Vote; import bisq.core.dao.vote.proposal.Proposal; import bisq.core.dao.vote.proposal.ProposalService; -import bisq.core.dao.vote.result.BooleanVoteResult; -import bisq.core.dao.vote.result.VoteResult; import bisq.core.locale.Res; import org.bitcoinj.core.Transaction; @@ -63,7 +63,7 @@ public class ProposalListItem implements BsqBlockChain.Listener { private final ReadableBsqBlockChain readableBsqBlockChain; private final BsqFormatter bsqFormatter; private final ChangeListener chainHeightListener; - private final ChangeListener voteResultChangeListener; + private final ChangeListener voteResultChangeListener; @Getter private TxConfidenceIndicator txConfidenceIndicator; @Getter @@ -111,7 +111,7 @@ public class ProposalListItem implements BsqBlockChain.Listener { readableBsqBlockChain.addListener(this); phaseChangeListener = (observable, oldValue, newValue) -> { - applyState(newValue, proposal.getVoteResult()); + applyState(newValue, proposal.getVote()); }; voteResultChangeListener = (observable, oldValue, newValue) -> { @@ -122,16 +122,17 @@ public class ProposalListItem implements BsqBlockChain.Listener { proposal.getVoteResultProperty().addListener(voteResultChangeListener); } - public void applyState(PeriodService.Phase newValue, VoteResult voteResult) { + public void applyState(PeriodService.Phase newValue, Vote vote) { actionButton.setText(""); actionButton.setVisible(false); actionButton.setOnAction(null); - final boolean isTxInPastCycle = periodService.isTxInPastCycle(proposal.getTxId()); + final boolean isTxInPastCycle = periodService.isTxInPastCycle(proposal.getTxId(), + readableBsqBlockChain.getChainHeadHeight()); switch (newValue) { case UNDEFINED: break; case PROPOSAL: - if (proposalService.isMine(proposal)) { + if (proposalService.isMine(proposal.getProposalPayload())) { actionButton.setVisible(!isTxInPastCycle); actionButtonIconView.setVisible(actionButton.isVisible()); actionButton.setText(Res.get("shared.remove")); @@ -150,10 +151,10 @@ public void applyState(PeriodService.Phase newValue, VoteResult voteResult) { if (!isTxInPastCycle) { actionNode = actionButtonIconView; actionButton.setVisible(false); - if (proposal.getVoteResult() != null) { + if (proposal.getVote() != null) { actionButtonIconView.setVisible(true); - if (voteResult instanceof BooleanVoteResult) { - if (((BooleanVoteResult) voteResult).isAccepted()) { + if (vote instanceof BooleanVote) { + if (((BooleanVote) vote).isAccepted()) { actionButtonIconView.setId("accepted"); } else { actionButtonIconView.setId("rejected"); @@ -162,7 +163,6 @@ public void applyState(PeriodService.Phase newValue, VoteResult voteResult) { //TODO } } else { - log.error("actionButtonIconView.setVisible(false);"); actionButtonIconView.setVisible(false); } } diff --git a/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java b/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java index 268c08d4fe8..5b8f40d5052 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/active/ActiveProposalsView.java @@ -18,41 +18,40 @@ package bisq.desktop.main.dao.proposal.active; import bisq.desktop.common.view.FxmlView; +import bisq.desktop.components.BusyAnimation; import bisq.desktop.components.InputTextField; import bisq.desktop.components.TitledGroupBg; import bisq.desktop.main.dao.proposal.BaseProposalView; import bisq.desktop.main.dao.proposal.ProposalListItem; import bisq.desktop.main.overlays.popups.Popup; +import bisq.desktop.util.BSFormatter; import bisq.desktop.util.BsqFormatter; +import bisq.desktop.util.GUIUtil; import bisq.desktop.util.Layout; import bisq.core.btc.exceptions.TransactionVerificationException; import bisq.core.btc.exceptions.WalletException; import bisq.core.btc.wallet.BsqBalanceListener; import bisq.core.btc.wallet.BsqWalletService; -import bisq.core.btc.wallet.InsufficientBsqException; import bisq.core.dao.blockchain.ReadableBsqBlockChain; +import bisq.core.dao.param.DaoParamService; +import bisq.core.dao.vote.BooleanVote; import bisq.core.dao.vote.PeriodService; +import bisq.core.dao.vote.blindvote.BlindVoteConsensus; import bisq.core.dao.vote.blindvote.BlindVoteService; import bisq.core.dao.vote.proposal.Proposal; import bisq.core.dao.vote.proposal.ProposalService; -import bisq.core.dao.vote.result.BooleanVoteResult; import bisq.core.locale.Res; -import bisq.common.crypto.CryptoException; import bisq.common.util.Tuple2; import bisq.common.util.Tuple3; -import com.google.protobuf.InvalidProtocolBufferException; - import org.bitcoinj.core.Coin; import org.bitcoinj.core.InsufficientMoneyException; import org.bitcoinj.core.Transaction; import javax.inject.Inject; -import com.google.common.util.concurrent.FutureCallback; - import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -64,20 +63,11 @@ import javafx.util.Callback; -import java.io.IOException; - import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; - -import static bisq.desktop.util.FormBuilder.add3ButtonsAfterGroup; -import static bisq.desktop.util.FormBuilder.addButtonAfterGroup; -import static bisq.desktop.util.FormBuilder.addLabelInputTextField; -import static bisq.desktop.util.FormBuilder.addTitledGroupBg; +import static bisq.desktop.util.FormBuilder.*; @FxmlView public class ActiveProposalsView extends BaseProposalView implements BsqBalanceListener { @@ -87,6 +77,8 @@ public class ActiveProposalsView extends BaseProposalView implements BsqBalanceL private Button removeButton, acceptButton, rejectButton, cancelVoteButton, voteButton; private InputTextField stakeInputTextField; private List voteViewItems = new ArrayList<>(); + private BusyAnimation voteButtonBusyAnimation; + private Label voteButtonInfoLabel; /////////////////////////////////////////////////////////////////////////////////////////// @@ -99,9 +91,11 @@ private ActiveProposalsView(ProposalService voteRequestManger, BlindVoteService blindVoteService, BsqWalletService bsqWalletService, ReadableBsqBlockChain readableBsqBlockChain, - BsqFormatter bsqFormatter) { - super(voteRequestManger, bsqWalletService, readableBsqBlockChain, periodService, - bsqFormatter); + DaoParamService daoParamService, + BsqFormatter bsqFormatter, + BSFormatter btcFormatter) { + super(voteRequestManger, bsqWalletService, readableBsqBlockChain, daoParamService, periodService, bsqFormatter, + btcFormatter); this.blindVoteService = blindVoteService; } @@ -128,41 +122,43 @@ protected void activate() { if (voteButton != null) { voteButton.setOnAction(e -> { - Coin stake = bsqFormatter.parseToCoin(stakeInputTextField.getText()); // TODO verify stake - //TODO show popup + Coin stake = bsqFormatter.parseToCoin(stakeInputTextField.getText()); + final Coin fee = BlindVoteConsensus.getFee(daoParamService, readableBsqBlockChain.getChainHeadHeight()); + Transaction dummyTx = null; try { - blindVoteService.publishBlindVote(stake, new FutureCallback() { - @Override - public void onSuccess(@Nullable Transaction result) { - //TODO - } + // We create a tx with dummy opreturn data to get the mining fee for confirmation popup + dummyTx = blindVoteService.getBlindVoteTx(stake, fee, new byte[22]); + } catch (InsufficientMoneyException | WalletException | TransactionVerificationException exception) { + new Popup<>().warning(exception.toString()).show(); + } - @Override - public void onFailure(@NotNull Throwable t) { - //TODO - } - }); - } catch (CryptoException e1) { - //TODO show error popup - e1.printStackTrace(); - } catch (InsufficientBsqException e1) { - e1.printStackTrace(); - } catch (WalletException e1) { - e1.printStackTrace(); - } catch (TransactionVerificationException e1) { - e1.printStackTrace(); - } catch (InsufficientMoneyException e1) { - e1.printStackTrace(); - } catch (InvalidProtocolBufferException e1) { - e1.printStackTrace(); - } catch (IOException e1) { - e1.printStackTrace(); + if (dummyTx != null) { + Coin miningFee = dummyTx.getFee(); + int txSize = dummyTx.bitcoinSerialize().length; + GUIUtil.showBsqFeeInfoPopup(fee, miningFee, txSize, bsqFormatter, btcFormatter, + Res.get("dao.blindVote"), () -> publishBlindVote(stake)); } }); } } + private void publishBlindVote(Coin stake) { + voteButtonBusyAnimation.play(); + voteButtonInfoLabel.setText(Res.get("dao.blindVote.startPublishing")); + blindVoteService.publishBlindVote(stake, + () -> { + voteButtonBusyAnimation.stop(); + voteButtonInfoLabel.setText(""); + new Popup().feedback(Res.get("dao.blindVote.success")) + .show(); + }, exception -> { + voteButtonBusyAnimation.stop(); + voteButtonInfoLabel.setText(""); + new Popup<>().warning(exception.toString()).show(); + }); + } + @Override protected void deactivate() { super.deactivate(); @@ -183,7 +179,10 @@ private void createVoteView() { Res.getWithCol("dao.proposal.myVote.stake"), Layout .FIRST_ROW_AND_GROUP_DISTANCE - 20); stakeInputTextField = tuple2.second; - voteButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.proposal.myVote.button")); + Tuple3 tuple = addButtonBusyAnimationLabelAfterGroup(root, ++gridRow, Res.get("dao.proposal.myVote.button")); + voteButton = tuple.first; + voteButtonBusyAnimation = tuple.second; + voteButtonInfoLabel = tuple.third; voteViewItems.add(titledGroupBg); voteViewItems.add(tuple2.first); @@ -236,17 +235,17 @@ protected void onSelectProposal(ProposalListItem item) { } private void onAccept() { - selectedProposalListItem.getProposal().setVoteResult(new BooleanVoteResult(true)); + selectedProposalListItem.getProposal().setVote(new BooleanVote(true)); updateStateAfterVote(); } private void onReject() { - selectedProposalListItem.getProposal().setVoteResult(new BooleanVoteResult(false)); + selectedProposalListItem.getProposal().setVote(new BooleanVote(false)); updateStateAfterVote(); } private void onCancelVote() { - selectedProposalListItem.getProposal().setVoteResult(null); + selectedProposalListItem.getProposal().setVote(null); updateStateAfterVote(); } @@ -263,11 +262,12 @@ protected void onPhaseChanged(PeriodService.Phase phase) { } if (selectedProposalListItem != null && proposalDisplay != null && - !periodService.isTxInPastCycle(selectedProposalListItem.getProposal().getTxId())) { + !periodService.isTxInPastCycle(selectedProposalListItem.getProposal().getTxId(), + readableBsqBlockChain.getChainHeadHeight())) { final Proposal proposal = selectedProposalListItem.getProposal(); switch (phase) { case PROPOSAL: - if (proposalService.isMine(proposal)) { + if (proposalService.isMine(proposal.getProposalPayload())) { if (removeButton == null) { removeButton = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.active.remove")); removeButton.setOnAction(event -> onRemove()); @@ -326,7 +326,7 @@ protected void onPhaseChanged(PeriodService.Phase phase) { @Override protected void updateProposalList() { - doUpdateProposalList(proposalService.getActiveProposals()); + doUpdateProposalList(proposalService.getActiveOrMyUnconfirmedProposals()); } private void updateStateAfterVote() { diff --git a/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java b/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java index 66ed8481b4f..8acd1359f61 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/closed/ClosedProposalsView.java @@ -19,10 +19,12 @@ import bisq.desktop.common.view.FxmlView; import bisq.desktop.main.dao.proposal.BaseProposalView; +import bisq.desktop.util.BSFormatter; import bisq.desktop.util.BsqFormatter; import bisq.core.btc.wallet.BsqWalletService; import bisq.core.dao.blockchain.ReadableBsqBlockChain; +import bisq.core.dao.param.DaoParamService; import bisq.core.dao.vote.PeriodService; import bisq.core.dao.vote.proposal.ProposalService; @@ -40,8 +42,11 @@ private ClosedProposalsView(ProposalService proposalService, PeriodService periodService, BsqWalletService bsqWalletService, ReadableBsqBlockChain readableBsqBlockChain, - BsqFormatter bsqFormatter) { - super(proposalService, bsqWalletService, readableBsqBlockChain, periodService, bsqFormatter); + DaoParamService daoParamService, + BsqFormatter bsqFormatter, + BSFormatter bsFormatter) { + super(proposalService, bsqWalletService, readableBsqBlockChain, daoParamService, periodService, + bsqFormatter, bsFormatter); } @Override diff --git a/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java b/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java index 6185f7dcdb6..57ae79d3b63 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/make/MakeProposalView.java @@ -44,7 +44,6 @@ import bisq.core.dao.vote.proposal.generic.GenericProposalService; import bisq.core.locale.Res; import bisq.core.provider.fee.FeeService; -import bisq.core.util.CoinUtil; import bisq.network.p2p.P2PService; @@ -175,25 +174,11 @@ private void publishProposal(ProposalType type) { Coin miningFee = Objects.requireNonNull(tx).getFee(); int txSize = tx.bitcoinSerialize().length; - final Coin fee = ProposalConsensus.getFee(daoParamService, readableBsqBlockChain); - new Popup<>().headLine(Res.get("dao.proposal.create.confirm")) - .confirmation(Res.get("dao.proposal.create.confirm.info", - bsqFormatter.formatCoinWithCode(fee), - btcFormatter.formatCoinWithCode(miningFee), - CoinUtil.getFeePerByte(miningFee, txSize), - txSize / 1000d)) - .actionButtonText(Res.get("shared.yes")) - .onAction(() -> { - proposalService.publishProposal(proposal, - () -> { - proposalDisplay.clearForm(); - proposalTypeComboBox.getSelectionModel().clearSelection(); - new Popup<>().confirmation(Res.get("dao.tx.published.success")).show(); - }, - errorMessage -> new Popup<>().warning(errorMessage).show()); - }) - .closeButtonText(Res.get("shared.cancel")) - .show(); + final Coin fee = ProposalConsensus.getFee(daoParamService, readableBsqBlockChain.getChainHeadHeight()); + + GUIUtil.showBsqFeeInfoPopup(fee, miningFee, txSize, bsqFormatter, btcFormatter, + Res.get("dao.proposal"), () -> publishProposal(proposal)); + } catch (InsufficientMoneyException e) { BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter; new Popup<>().warning(Res.get("dao.proposal.create.missingFunds", @@ -214,6 +199,16 @@ private void publishProposal(ProposalType type) { } } + private void publishProposal(Proposal proposal) { + proposalService.publishProposal(proposal, + () -> { + proposalDisplay.clearForm(); + proposalTypeComboBox.getSelectionModel().clearSelection(); + new Popup<>().confirmation(Res.get("dao.tx.published.success")).show(); + }, + errorMessage -> new Popup<>().warning(errorMessage).show()); + } + private Proposal createProposal(ProposalType type) throws InsufficientMoneyException, TransactionVerificationException, ValidationException, WalletException, IOException { diff --git a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java index d319b68dd52..02bb9b869e3 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/MyVotesView.java @@ -24,18 +24,20 @@ import bisq.desktop.components.TableGroupHeadline; import bisq.desktop.main.dao.proposal.BaseProposalView; import bisq.desktop.main.dao.proposal.ProposalListItem; +import bisq.desktop.util.BSFormatter; import bisq.desktop.util.BsqFormatter; import bisq.desktop.util.GUIUtil; import bisq.desktop.util.Layout; import bisq.core.btc.wallet.BsqWalletService; import bisq.core.dao.blockchain.ReadableBsqBlockChain; +import bisq.core.dao.param.DaoParamService; +import bisq.core.dao.vote.BooleanVote; import bisq.core.dao.vote.PeriodService; +import bisq.core.dao.vote.Vote; import bisq.core.dao.vote.myvote.MyVoteService; import bisq.core.dao.vote.proposal.ProposalList; import bisq.core.dao.vote.proposal.ProposalService; -import bisq.core.dao.vote.result.BooleanVoteResult; -import bisq.core.dao.vote.result.VoteResult; import bisq.core.locale.Res; import bisq.core.user.Preferences; @@ -92,10 +94,12 @@ private MyVotesView(ProposalService voteRequestManger, MyVoteService myVoteService, BsqWalletService bsqWalletService, ReadableBsqBlockChain readableBsqBlockChain, + DaoParamService daoParamService, Preferences preferences, - BsqFormatter bsqFormatter) { - super(voteRequestManger, bsqWalletService, readableBsqBlockChain, periodService, - bsqFormatter); + BsqFormatter bsqFormatter, + BSFormatter btcFormatter) { + super(voteRequestManger, bsqWalletService, readableBsqBlockChain, daoParamService, periodService, bsqFormatter, + btcFormatter); this.myVoteService = myVoteService; this.readableBsqBlockChain = readableBsqBlockChain; this.preferences = preferences; @@ -371,9 +375,9 @@ public void updateItem(final ProposalListItem item, boolean empty) { if (item != null && !empty) { actionButtonIconView = new ImageView(); - VoteResult voteResult = item.getProposal().getVoteResult(); - if (voteResult instanceof BooleanVoteResult) { - if (((BooleanVoteResult) voteResult).isAccepted()) { + Vote vote = item.getProposal().getVote(); + if (vote instanceof BooleanVote) { + if (((BooleanVote) vote).isAccepted()) { actionButtonIconView.setId("accepted"); } else { actionButtonIconView.setId("rejected"); diff --git a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java index 62e441cda2d..6ddcfbf5e08 100644 --- a/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java +++ b/src/main/java/bisq/desktop/main/dao/proposal/myvotes/VoteListItem.java @@ -149,7 +149,7 @@ public void onTransactionConfidenceChanged(TransactionConfidence confidence) { private void calculateStake() { if (stake == 0) { String txId = myVote.getTxId(); - stake = readableBsqBlockChain.getBlindVoteStakeTxOutputs().stream() + stake = readableBsqBlockChain.getUnspentBlindVoteStakeTxOutputs().stream() .filter(txOutput -> txOutput.getTxId().equals(txId)) .filter(txOutput -> txOutput.getIndex() == 0) .mapToLong(TxOutput::getValue) diff --git a/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java b/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java index a1dac3b057e..3d78201af99 100644 --- a/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java +++ b/src/main/java/bisq/desktop/main/dao/wallet/dashboard/BsqDashboardView.java @@ -66,8 +66,8 @@ public class BsqDashboardView extends ActivatableView implements private final BsqFormatter bsqFormatter; private int gridRow = 0; - private TextField issuedAmountTextField, availableAmountTextField, burntAmountTextField, allTxTextField, - burntTxTextField, spentTxTextField, + private TextField genesisIssueAmountTextField, compRequestIssueAmountTextField, availableAmountTextField, burntAmountTextField, allTxTextField, + burntTxTextField/*, spentTxTextField*/, utxoTextField, priceTextField, marketCapTextField; private ChangeListener priceChangeListener; private HyperlinkWithIcon hyperlinkWithIcon; @@ -94,7 +94,7 @@ private BsqDashboardView(BsqBalanceUtil bsqBalanceUtil, public void initialize() { gridRow = bsqBalanceUtil.addGroup(root, gridRow); - addTitledGroupBg(root, ++gridRow, 12, Res.get("dao.wallet.dashboard.statistics"), Layout.GROUP_DISTANCE); + addTitledGroupBg(root, ++gridRow, 11, Res.get("dao.wallet.dashboard.statistics"), Layout.GROUP_DISTANCE); addLabelTextField(root, gridRow, Res.get("dao.wallet.dashboard.genesisBlockHeight"), String.valueOf(readableBsqBlockChain.getGenesisBlockHeight()), Layout.FIRST_ROW_AND_GROUP_DISTANCE); @@ -109,13 +109,14 @@ public void initialize() { GridPane.setMargin(hyperlinkWithIcon, new Insets(0, 0, 0, -4)); root.getChildren().add(hyperlinkWithIcon); - issuedAmountTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.issuedAmount")).second; + genesisIssueAmountTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.genesisIssueAmount")).second; + compRequestIssueAmountTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.compRequestIssueAmount")).second; availableAmountTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.availableAmount")).second; burntAmountTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.burntAmount")).second; allTxTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.allTx")).second; utxoTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.utxo")).second; - spentTxTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.spentTxo")).second; + // spentTxTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.spentTxo")).second; burntTxTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.burntTx")).second; priceTextField = addLabelTextField(root, ++gridRow, Res.get("dao.wallet.dashboard.price")).second; @@ -157,14 +158,20 @@ public void onBlockAdded(BsqBlock bsqBlock) { private void updateWithBsqBlockChainData() { - issuedAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(readableBsqBlockChain.getIssuedAmountAtGenesis())); + final Coin issuedAmountFromGenesis = readableBsqBlockChain.getIssuedAmountAtGenesis(); + genesisIssueAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromGenesis)); + + final Coin issuedAmountFromCompRequests = readableBsqBlockChain.getIssuedAmountFromCompRequests(); + compRequestIssueAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(issuedAmountFromCompRequests)); + final Coin burntFee = readableBsqBlockChain.getTotalBurntFee(); - final Coin availableAmount = readableBsqBlockChain.getIssuedAmountAtGenesis().subtract(burntFee); + final Coin availableAmount = issuedAmountFromGenesis.add(issuedAmountFromCompRequests).subtract(burntFee); + availableAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(availableAmount)); burntAmountTextField.setText(bsqFormatter.formatAmountWithGroupSeparatorAndCode(burntFee)); allTxTextField.setText(String.valueOf(readableBsqBlockChain.getTransactions().size())); utxoTextField.setText(String.valueOf(readableBsqBlockChain.getUnspentTxOutputs().size())); - spentTxTextField.setText(String.valueOf(readableBsqBlockChain.getSpentTxOutputs().size())); + //spentTxTextField.setText(String.valueOf(readableBsqBlockChain.getSpentTxOutputs().size())); burntTxTextField.setText(String.valueOf(readableBsqBlockChain.getFeeTransactions().size())); } diff --git a/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java b/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java index 21b2d9d7d84..b7087db1e9e 100644 --- a/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java +++ b/src/main/java/bisq/desktop/main/dao/wallet/send/BsqSendView.java @@ -37,6 +37,10 @@ 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.locale.Res; @@ -50,17 +54,11 @@ import javax.inject.Inject; -import com.google.common.util.concurrent.FutureCallback; - import javafx.scene.control.Button; import javafx.scene.layout.GridPane; import javafx.beans.value.ChangeListener; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; - import static bisq.desktop.util.FormBuilder.addButtonAfterGroup; import static bisq.desktop.util.FormBuilder.addLabelInputTextField; import static bisq.desktop.util.FormBuilder.addTitledGroupBg; @@ -159,18 +157,28 @@ public void initialize() { bsqFormatter.formatCoinWithCode(receiverAmount))) .actionButtonText(Res.get("shared.yes")) .onAction(() -> { - walletsManager.publishAndCommitBsqTx(txWithBtcFee, new FutureCallback() { + walletsManager.publishAndCommitBsqTx(txWithBtcFee, new TxBroadcaster.Callback() { + @Override + public void onSuccess(Transaction transaction) { + log.debug("Successfully sent tx with id " + txWithBtcFee.getHashAsString()); + } + + @Override + public void onTimeout(TxBroadcastTimeoutException exception) { + //TODO handle + new Popup<>().warning(exception.toString()); + } + @Override - public void onSuccess(@Nullable Transaction transaction) { - if (transaction != null) { - log.debug("Successfully sent tx with id " + transaction.getHashAsString()); - } + public void onTxMalleability(TxMalleabilityException exception) { + //TODO handle + new Popup<>().warning(exception.toString()); } @Override - public void onFailure(@NotNull Throwable t) { - log.error(t.toString()); - new Popup<>().warning(t.toString()); + public void onFailure(TxBroadcastException exception) { + //TODO handle + new Popup<>().warning(exception.toString()); } }); diff --git a/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java b/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java index 96f9163f555..5b45e9e2e51 100644 --- a/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java +++ b/src/main/java/bisq/desktop/main/overlays/windows/ManualPayoutTxWindow.java @@ -25,6 +25,8 @@ import bisq.core.btc.exceptions.TransactionVerificationException; import bisq.core.btc.exceptions.WalletException; import bisq.core.btc.wallet.TradeWalletService; +import bisq.core.btc.wallet.TxBroadcastException; +import bisq.core.btc.wallet.TxBroadcaster; import bisq.core.btc.wallet.WalletsSetup; import bisq.network.p2p.P2PService; @@ -37,16 +39,12 @@ import javax.inject.Inject; -import com.google.common.util.concurrent.FutureCallback; - import javafx.scene.Scene; import javafx.scene.input.KeyCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.jetbrains.annotations.NotNull; - import javax.annotation.Nullable; import static bisq.desktop.util.FormBuilder.addLabelInputTextField; @@ -154,7 +152,7 @@ private void addContent() { actionButtonText("Sign and publish transaction"); - FutureCallback callback = new FutureCallback() { + TxBroadcaster.Callback callback = new TxBroadcaster.Callback() { @Override public void onSuccess(@Nullable Transaction result) { log.error("onSuccess"); @@ -167,10 +165,9 @@ public void onSuccess(@Nullable Transaction result) { } @Override - public void onFailure(@NotNull Throwable t) { - log.error(t.toString()); - log.error("onFailure"); - UserThread.execute(() -> new Popup<>().warning(t.toString()).show()); + public void onFailure(TxBroadcastException exception) { + log.error(exception.toString()); + UserThread.execute(() -> new Popup<>().warning(exception.toString()).show()); } }; onAction(() -> { diff --git a/src/main/java/bisq/desktop/util/GUIUtil.java b/src/main/java/bisq/desktop/util/GUIUtil.java index 0c8271c01fc..1824148c1a4 100644 --- a/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/src/main/java/bisq/desktop/util/GUIUtil.java @@ -33,6 +33,7 @@ import bisq.core.user.DontShowAgainLookup; import bisq.core.user.Preferences; import bisq.core.user.User; +import bisq.core.util.CoinUtil; import bisq.network.p2p.P2PService; @@ -543,4 +544,21 @@ public static void removeChildrenFromGridPaneRows(GridPane gridPane, int start, childByRowMap.get(i).forEach(child -> gridPane.getChildren().remove(child)); } } + + public static void showBsqFeeInfoPopup(Coin fee, Coin miningFee, int txSize, BsqFormatter bsqFormatter, + BSFormatter btcFormatter, String type, + Runnable actionHandler) { + new Popup<>().headLine(Res.get("dao.feeTx.confirm", type)) + .confirmation(Res.get("dao.feeTx.confirm.details", + type, + bsqFormatter.formatCoinWithCode(fee), + btcFormatter.formatCoinWithCode(miningFee), + CoinUtil.getFeePerByte(miningFee, txSize), + txSize / 1000d, + type)) + .actionButtonText(Res.get("shared.yes")) + .onAction(actionHandler::run) + .closeButtonText(Res.get("shared.cancel")) + .show(); + } }