Fix BSQ balance display for unconfirmed change outputs

- Add verifiedBsqBalance and unconfirmedChangeBalance
- Remove totalBsqBalance
- Make text for different balances more explicit
This commit is contained in:
Manfred Karrer 2019-03-03 15:05:19 -05:00
parent 9475cf2897
commit 1802508c7c
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
8 changed files with 117 additions and 70 deletions

View file

@ -103,7 +103,8 @@ public abstract class BisqDefaultCoinSelector implements CoinSelector {
return Coin.valueOf(change);
}
// We allow spending own pending txs and if permitForeignPendingTx is set as well foreign unconfirmed txs.
// We allow spending from own unconfirmed txs and if permitForeignPendingTx is set as well from foreign
// unconfirmed txs.
protected boolean isTxSpendable(Transaction tx) {
TransactionConfidence confidence = tx.getConfidence();
TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();

View file

@ -39,7 +39,8 @@ public class BsqCoinSelector extends BisqDefaultCoinSelector {
@Inject
public BsqCoinSelector(DaoStateService daoStateService, UnconfirmedBsqChangeOutputListService unconfirmedBsqChangeOutputListService) {
super(true);
// permitForeignPendingTx is not relevant here as we do not support pending foreign utxos anyway.
super(false);
this.daoStateService = daoStateService;
this.unconfirmedBsqChangeOutputListService = unconfirmedBsqChangeOutputListService;
}

View file

@ -191,8 +191,10 @@ public class BsqWalletService extends WalletService implements DaoStateListener
@Override
public void onParseTxsCompleteAfterBatchProcessing(Block block) {
if (isWalletReady())
if (isWalletReady()) {
wallet.getTransactions(false).forEach(unconfirmedBsqChangeOutputListService::onTransactionConfidenceChanged);
updateBsqWalletTransactions();
}
}
@ -249,6 +251,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
})
.sum()
);
Set<String> confirmedTxIdSet = getTransactions(false).stream()
.filter(tx -> tx.getConfidence().getConfidenceType() == BUILDING)
.map(Transaction::getHashAsString)

View file

@ -55,7 +55,10 @@ public class WalletsManager {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public WalletsManager(BtcWalletService btcWalletService, TradeWalletService tradeWalletService, BsqWalletService bsqWalletService, WalletsSetup walletsSetup) {
public WalletsManager(BtcWalletService btcWalletService,
TradeWalletService tradeWalletService,
BsqWalletService bsqWalletService,
WalletsSetup walletsSetup) {
this.btcWalletService = btcWalletService;
this.tradeWalletService = tradeWalletService;
this.bsqWalletService = bsqWalletService;

View file

@ -53,6 +53,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
@ -68,6 +69,7 @@ public class DaoStateService implements DaoSetupService {
private final GenesisTxInfo genesisTxInfo;
private final BsqFormatter bsqFormatter;
private final List<DaoStateListener> daoStateListeners = new CopyOnWriteArrayList<>();
@Getter
private boolean parseBlockChainComplete;

View file

@ -47,6 +47,11 @@ public class UnconfirmedBsqChangeOutputListService implements PersistedDataHost
this.storage = storage;
}
///////////////////////////////////////////////////////////////////////////////////////////
// PersistedDataHost
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void readPersisted() {
if (DevEnv.isDaoActivated()) {

View file

@ -1228,11 +1228,13 @@ dao.tab.proofOfBurn=Asset listing fee/Proof of burn
dao.tab.news=News
dao.paidWithBsq=paid with BSQ
dao.availableBsqBalance=Available
dao.availableNonBsqBalance=Available non-BSQ balance (BTC)
dao.unverifiedBsqBalance=Unverified (awaiting block confirmation)
dao.availableBsqBalance=Available for spending (verified + unconfirmed change outputs)
dao.verifiedBsqBalance=Balance of all verified UTXOs
dao.unconfirmedChangeBalance=Balance of all unconfirmed change outputs
dao.unverifiedBsqBalance=Balance of all unverified transactions (awaiting block confirmation)
dao.lockedForVoteBalance=Used for voting
dao.lockedInBonds=Locked in bonds
dao.availableNonBsqBalance=Available non-BSQ balance (BTC)
dao.totalBsqBalance=Total BSQ balance
dao.tx.published.success=Your transaction has been successfully published.

View file

@ -17,12 +17,14 @@
package bisq.desktop.main.dao.wallet;
import bisq.desktop.components.TitledGroupBg;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.core.btc.listeners.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.state.DaoStateListener;
import bisq.core.dao.state.DaoStateService;
import bisq.core.dao.state.model.blockchain.Block;
import bisq.core.locale.Res;
import bisq.core.util.BsqFormatter;
@ -42,45 +44,127 @@ import lombok.extern.slf4j.Slf4j;
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
@Slf4j
public class BsqBalanceUtil implements BsqBalanceListener {
public class BsqBalanceUtil implements BsqBalanceListener, DaoStateListener {
private final BsqWalletService bsqWalletService;
private final DaoStateService daoStateService;
private final BsqFormatter bsqFormatter;
// Displaying general BSQ info
private TextField availableBalanceTextField, availableNonBsqBalanceTextField, unverifiedBalanceTextField, lockedForVoteBalanceTextField,
lockedInBondsBalanceTextField, totalBalanceTextField;
private TextField availableBalanceTextField, verifiedBalanceTextField, availableNonBsqBalanceTextField,
unverifiedBalanceTextField, lockedForVoteBalanceTextField,
lockedInBondsBalanceTextField, unconfirmedChangTextField;
// Displaying bond dashboard info
private TextField lockupAmountTextField, unlockingAmountTextField;
private TitledGroupBg titledGroupBg;
private Label availableNonBsqBalanceLabel;
@Inject
private BsqBalanceUtil(BsqWalletService bsqWalletService,
DaoStateService daoStateService,
BsqFormatter bsqFormatter) {
this.bsqWalletService = bsqWalletService;
this.daoStateService = daoStateService;
this.bsqFormatter = bsqFormatter;
}
public void activate() {
bsqWalletService.addBsqBalanceListener(this);
daoStateService.addBsqStateListener(this);
triggerUpdate();
}
public void deactivate() {
bsqWalletService.removeBsqBalanceListener(this);
daoStateService.removeBsqStateListener(this);
}
///////////////////////////////////////////////////////////////////////////////////////////
// DaoStateListener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onParseTxsCompleteAfterBatchProcessing(Block block) {
bsqWalletService.addBsqBalanceListener(this);
triggerUpdate();
}
///////////////////////////////////////////////////////////////////////////////////////////
// BsqBalanceListener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onUpdateBalances(Coin availableBalance,
Coin availableNonBsqBalance,
Coin unverifiedBalance,
Coin unconfirmedChangeBalance,
Coin lockedForVotingBalance,
Coin lockupBondsBalance,
Coin unlockingBondsBalance) {
boolean isNonBsqBalanceAvailable = availableNonBsqBalance.value > 0;
availableBalanceTextField.setText(bsqFormatter.formatCoinWithCode(availableBalance));
Coin verified = availableBalance.subtract(unconfirmedChangeBalance);
verifiedBalanceTextField.setText(bsqFormatter.formatCoinWithCode(verified));
unconfirmedChangTextField.setText(bsqFormatter.formatCoinWithCode(unconfirmedChangeBalance));
unverifiedBalanceTextField.setText(bsqFormatter.formatCoinWithCode(unverifiedBalance));
lockedForVoteBalanceTextField.setText(bsqFormatter.formatCoinWithCode(lockedForVotingBalance));
lockedInBondsBalanceTextField.setText(bsqFormatter.formatCoinWithCode(
lockupBondsBalance.add(unlockingBondsBalance)));
if (lockupAmountTextField != null && unlockingAmountTextField != null) {
lockupAmountTextField.setText(bsqFormatter.formatCoinWithCode(lockupBondsBalance));
unlockingAmountTextField.setText(bsqFormatter.formatCoinWithCode(unlockingBondsBalance));
}
availableNonBsqBalanceLabel.setVisible(isNonBsqBalanceAvailable);
availableNonBsqBalanceLabel.setManaged(isNonBsqBalanceAvailable);
availableNonBsqBalanceTextField.setVisible(isNonBsqBalanceAvailable);
availableNonBsqBalanceTextField.setManaged(isNonBsqBalanceAvailable);
availableNonBsqBalanceTextField.setText(bsqFormatter.formatBTCWithCode(availableNonBsqBalance.value));
}
private void triggerUpdate() {
onUpdateBalances(bsqWalletService.getAvailableConfirmedBalance(),
bsqWalletService.getAvailableNonBsqBalance(),
bsqWalletService.getUnverifiedBalance(),
bsqWalletService.getUnconfirmedChangeBalance(),
bsqWalletService.getLockedForVotingBalance(),
bsqWalletService.getLockupBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public int addGroup(GridPane gridPane, int gridRow) {
int startIndex = gridRow;
titledGroupBg = addTitledGroupBg(gridPane, gridRow, 3, Res.get("dao.wallet.dashboard.myBalance"));
addTitledGroupBg(gridPane, gridRow, 4, Res.get("dao.wallet.dashboard.myBalance"));
availableBalanceTextField = FormBuilder.addTopLabelReadOnlyTextField(gridPane, gridRow,
Res.get("dao.availableBsqBalance"), Layout.FIRST_ROW_DISTANCE).second;
verifiedBalanceTextField = FormBuilder.addTopLabelReadOnlyTextField(gridPane, ++gridRow,
Res.get("dao.verifiedBsqBalance")).second;
unconfirmedChangTextField = FormBuilder.addTopLabelReadOnlyTextField(gridPane, ++gridRow,
Res.get("dao.unconfirmedChangeBalance")).second;
unverifiedBalanceTextField = FormBuilder.addTopLabelReadOnlyTextField(gridPane, ++gridRow,
Res.get("dao.unverifiedBsqBalance")).second;
totalBalanceTextField = FormBuilder.addTopLabelReadOnlyTextField(gridPane, ++gridRow,
Res.get("dao.totalBsqBalance")).second;
gridRow = startIndex;
int columnIndex = 2;
titledGroupBg = addTitledGroupBg(gridPane, gridRow, columnIndex, 3, "");
addTitledGroupBg(gridPane, gridRow, columnIndex, 4, "");
lockedForVoteBalanceTextField = FormBuilder.addTopLabelReadOnlyTextField(gridPane, gridRow, columnIndex,
Res.get("dao.lockedForVoteBalance"), Layout.FIRST_ROW_DISTANCE).second;
lockedInBondsBalanceTextField = FormBuilder.addTopLabelReadOnlyTextField(gridPane, ++gridRow, columnIndex,
Res.get("dao.lockedInBonds")).second;
Tuple3<Label, TextField, VBox> tuple3 = FormBuilder.addTopLabelReadOnlyTextField(gridPane, ++gridRow, columnIndex,
Res.get("dao.availableNonBsqBalance"));
// Match left column
++gridRow;
// TODO add unlockingBondsBalanceTextField
@ -104,58 +188,4 @@ public class BsqBalanceUtil implements BsqBalanceListener {
return gridRow;
}
public void activate() {
onUpdateBalances(bsqWalletService.getAvailableConfirmedBalance(),
bsqWalletService.getAvailableNonBsqBalance(),
bsqWalletService.getUnverifiedBalance(),
bsqWalletService.getUnconfirmedChangeBalance(),
bsqWalletService.getLockedForVotingBalance(),
bsqWalletService.getLockupBondsBalance(),
bsqWalletService.getUnlockingBondsBalance());
bsqWalletService.addBsqBalanceListener(this);
}
public void deactivate() {
bsqWalletService.removeBsqBalanceListener(this);
}
@Override
public void onUpdateBalances(Coin availableBalance,
Coin availableNonBsqBalance,
Coin unverifiedBalance,
Coin unconfirmedChangeBalance,
Coin lockedForVotingBalance,
Coin lockupBondsBalance,
Coin unlockingBondsBalance) {
boolean isNonBsqBalanceAvailable = availableNonBsqBalance.value > 0;
//TODO MK
// Coin availableAndChange = availableBalance.add(unconfirmedChangeBalance);
availableBalanceTextField.setText(bsqFormatter.formatCoinWithCode(availableBalance));
unverifiedBalanceTextField.setText(bsqFormatter.formatCoinWithCode(unverifiedBalance));
lockedForVoteBalanceTextField.setText(bsqFormatter.formatCoinWithCode(lockedForVotingBalance));
lockedInBondsBalanceTextField.setText(bsqFormatter.formatCoinWithCode(
lockupBondsBalance.add(unlockingBondsBalance)));
if (lockupAmountTextField != null && unlockingAmountTextField != null) {
lockupAmountTextField.setText(bsqFormatter.formatCoinWithCode(lockupBondsBalance));
unlockingAmountTextField.setText(bsqFormatter.formatCoinWithCode(unlockingBondsBalance));
}
availableNonBsqBalanceLabel.setVisible(isNonBsqBalanceAvailable);
availableNonBsqBalanceLabel.setManaged(isNonBsqBalanceAvailable);
availableNonBsqBalanceTextField.setVisible(isNonBsqBalanceAvailable);
availableNonBsqBalanceTextField.setManaged(isNonBsqBalanceAvailable);
availableNonBsqBalanceTextField.setText(bsqFormatter.formatBTCWithCode(availableNonBsqBalance.value));
final Coin total = availableBalance
.add(unverifiedBalance)
.add(lockedForVotingBalance)
.add(lockupBondsBalance)
.add(unlockingBondsBalance);
totalBalanceTextField.setText(bsqFormatter.formatCoinWithCode(total));
}
}