diff --git a/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java b/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java index b5ab08bc00..fdb2c999e9 100644 --- a/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java +++ b/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java @@ -38,6 +38,8 @@ class ColumnHeaderConstants { static final String COL_HEADER_RESERVED_BALANCE = "Reserved Balance"; static final String COL_HEADER_TOTAL_AVAILABLE_BALANCE = "Total Available Balance"; static final String COL_HEADER_LOCKED_BALANCE = "Locked Balance"; + static final String COL_HEADER_RESERVED_OFFER_BALANCE = "Reserved Offer Balance"; + static final String COL_HEADER_RESERVED_TRADE_BALANCE = "Reserved Trade Balance"; static final String COL_HEADER_LOCKED_FOR_VOTING_BALANCE = "Locked For Voting Balance"; static final String COL_HEADER_LOCKUP_BONDS_BALANCE = "Lockup Bonds Balance"; static final String COL_HEADER_UNLOCKING_BONDS_BALANCE = "Unlocking Bonds Balance"; diff --git a/cli/src/main/java/bisq/cli/TableFormat.java b/cli/src/main/java/bisq/cli/TableFormat.java index 032264e3d8..73afcf40ce 100644 --- a/cli/src/main/java/bisq/cli/TableFormat.java +++ b/cli/src/main/java/bisq/cli/TableFormat.java @@ -121,19 +121,19 @@ public class TableFormat { public static String formatXmrBalanceInfoTbl(XmrBalanceInfo xmrBalanceInfo) { String headerLine = COL_HEADER_BALANCE + COL_HEADER_DELIMITER + COL_HEADER_AVAILABLE_BALANCE + COL_HEADER_DELIMITER - + COL_HEADER_RESERVED_BALANCE + COL_HEADER_DELIMITER - + COL_HEADER_TOTAL_AVAILABLE_BALANCE + COL_HEADER_DELIMITER // TODO (woodser): column names are not quite right for XMR (balance, available balance, locked balance, reserved balance, total balance) - + COL_HEADER_LOCKED_BALANCE + COL_HEADER_DELIMITER + "\n"; + + COL_HEADER_LOCKED_BALANCE + COL_HEADER_DELIMITER + + COL_HEADER_RESERVED_OFFER_BALANCE + COL_HEADER_DELIMITER + + COL_HEADER_RESERVED_TRADE_BALANCE + COL_HEADER_DELIMITER + "\n"; String colDataFormat = "%" + COL_HEADER_BALANCE.length() + "s" // rt justify + " %" + (COL_HEADER_AVAILABLE_BALANCE.length() + 1) + "s" // rt justify + + " %" + (COL_HEADER_LOCKED_BALANCE.length() + 1) + "s" // rt justify + " %" + (COL_HEADER_RESERVED_BALANCE.length() + 1) + "s" // rt justify - + " %" + (COL_HEADER_TOTAL_AVAILABLE_BALANCE.length() + 1) + "s" // rt justify - + " %" + (COL_HEADER_LOCKED_BALANCE.length() + 1) + "s"; // rt justify + + " %" + (COL_HEADER_TOTAL_AVAILABLE_BALANCE.length() + 1) + "s"; // rt justify return headerLine + format(colDataFormat, - formatSatoshis(xmrBalanceInfo.getAvailableBalance()), - formatSatoshis(xmrBalanceInfo.getReservedBalance()), - formatSatoshis(xmrBalanceInfo.getTotalBalance()), - formatSatoshis(xmrBalanceInfo.getLockedBalance())); + formatSatoshis(xmrBalanceInfo.getUnlockedBalance() + xmrBalanceInfo.getLockedBalance()), // total balance + formatSatoshis(xmrBalanceInfo.getUnlockedBalance()), + formatSatoshis(xmrBalanceInfo.getReservedOfferBalance()), + formatSatoshis(xmrBalanceInfo.getReservedTradeBalance())); } public static String formatPaymentAcctTbl(List paymentAccounts) { diff --git a/core/src/main/java/bisq/core/api/CoreWalletsService.java b/core/src/main/java/bisq/core/api/CoreWalletsService.java index d1687b1d4b..f05d8b6f35 100644 --- a/core/src/main/java/bisq/core/api/CoreWalletsService.java +++ b/core/src/main/java/bisq/core/api/CoreWalletsService.java @@ -635,20 +635,23 @@ class CoreWalletsService { var availableBalance = balances.getAvailableBalance().get(); if (availableBalance == null) throw new IllegalStateException("available balance is not yet available"); - - var reservedBalance = balances.getReservedBalance().get(); - if (reservedBalance == null) - throw new IllegalStateException("reserved balance is not yet available"); - + var lockedBalance = balances.getLockedBalance().get(); if (lockedBalance == null) throw new IllegalStateException("locked balance is not yet available"); + + var reservedOfferBalance = balances.getReservedOfferBalance().get(); + if (reservedOfferBalance == null) + throw new IllegalStateException("reserved offer balance is not yet available"); + + var reservedTradeBalance = balances.getReservedTradeBalance().get(); + if (reservedTradeBalance == null) + throw new IllegalStateException("reserved trade balance is not yet available"); - return new XmrBalanceInfo(availableBalance.add(lockedBalance).value, - availableBalance.value, - lockedBalance.value, - reservedBalance.value, - availableBalance.add(lockedBalance).add(reservedBalance).value); + return new XmrBalanceInfo(availableBalance.longValue(), + lockedBalance.longValue(), + reservedOfferBalance.longValue(), + reservedTradeBalance.longValue()); } // Returns a Coin for the transfer amount string, or a RuntimeException if invalid. diff --git a/core/src/main/java/bisq/core/api/model/XmrBalanceInfo.java b/core/src/main/java/bisq/core/api/model/XmrBalanceInfo.java index 4c2c84d07f..a4e798433b 100644 --- a/core/src/main/java/bisq/core/api/model/XmrBalanceInfo.java +++ b/core/src/main/java/bisq/core/api/model/XmrBalanceInfo.java @@ -10,42 +10,35 @@ import lombok.Getter; public class XmrBalanceInfo implements Payload { public static final XmrBalanceInfo EMPTY = new XmrBalanceInfo(-1, - -1, -1, -1, -1); - // All balances are in XMR centineros: https://www.getmonero.org/resources/moneropedia/denominations.html - private final long balance; - private final long availableBalance; + // all balances are in atomic units + private final long unlockedBalance; private final long lockedBalance; - private final long reservedBalance; - private final long totalBalance; // balance + reserved + private final long reservedOfferBalance; + private final long reservedTradeBalance; - public XmrBalanceInfo(long balance, - long availableBalance, + public XmrBalanceInfo(long unlockedBalance, long lockedBalance, - long reservedBalance, - long totalBalance) { - this.balance = balance; - this.availableBalance = availableBalance; + long reservedOfferBalance, + long reservedTradeBalance) { + this.unlockedBalance = unlockedBalance; this.lockedBalance = lockedBalance; - this.reservedBalance = reservedBalance; - this.totalBalance = totalBalance; + this.reservedOfferBalance = reservedOfferBalance; + this.reservedTradeBalance = reservedTradeBalance; } @VisibleForTesting - public static XmrBalanceInfo valueOf(long balance, - long availableBalance, + public static XmrBalanceInfo valueOf(long unlockedBalance, long lockedBalance, - long reservedBalance, - long totalBalance) { - // Convenience for creating a model instance instead of a proto. - return new XmrBalanceInfo(balance, - availableBalance, + long reservedOfferBalance, + long reservedTradeBalance) { + return new XmrBalanceInfo(unlockedBalance, lockedBalance, - reservedBalance, - totalBalance); + reservedOfferBalance, + reservedTradeBalance); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -55,30 +48,27 @@ public class XmrBalanceInfo implements Payload { @Override public bisq.proto.grpc.XmrBalanceInfo toProtoMessage() { return bisq.proto.grpc.XmrBalanceInfo.newBuilder() - .setBalance(balance) - .setAvailableBalance(availableBalance) + .setUnlockedBalance(unlockedBalance) .setLockedBalance(lockedBalance) - .setReservedBalance(reservedBalance) - .setTotalBalance(totalBalance) + .setReservedOfferBalance(reservedOfferBalance) + .setReservedTradeBalance(reservedTradeBalance) .build(); } public static XmrBalanceInfo fromProto(bisq.proto.grpc.XmrBalanceInfo proto) { - return new XmrBalanceInfo(proto.getBalance(), - proto.getAvailableBalance(), + return new XmrBalanceInfo(proto.getUnlockedBalance(), proto.getLockedBalance(), - proto.getReservedBalance(), - proto.getTotalBalance()); + proto.getReservedOfferBalance(), + proto.getReservedTradeBalance()); } @Override public String toString() { return "BtcBalanceInfo{" + - "balance=" + balance + - ", availableBalance=" + availableBalance + + "unlockedBalance=" + unlockedBalance + ", lockedBalance=" + lockedBalance + - ", reservedBalance=" + reservedBalance + - ", totalBalance=" + totalBalance + + ", reservedOfferBalance=" + reservedOfferBalance + + ", reservedTradeBalance=" + reservedTradeBalance + '}'; } } diff --git a/core/src/main/java/bisq/core/btc/Balances.java b/core/src/main/java/bisq/core/btc/Balances.java index 6c6dc9a81b..fa0416740b 100644 --- a/core/src/main/java/bisq/core/btc/Balances.java +++ b/core/src/main/java/bisq/core/btc/Balances.java @@ -56,9 +56,13 @@ public class Balances { @Getter private final ObjectProperty availableBalance = new SimpleObjectProperty<>(); @Getter - private final ObjectProperty reservedBalance = new SimpleObjectProperty<>(); - @Getter private final ObjectProperty lockedBalance = new SimpleObjectProperty<>(); + @Getter + private final ObjectProperty reservedOfferBalance = new SimpleObjectProperty<>(); + @Getter + private final ObjectProperty reservedTradeBalance = new SimpleObjectProperty<>(); + @Getter + private final ObjectProperty reservedBalance = new SimpleObjectProperty<>(); // TODO (woodser): this balance is sum of reserved funds for offers and trade multisigs; remove? @Inject public Balances(TradeManager tradeManager, @@ -92,6 +96,8 @@ public class Balances { UserThread.execute(() -> { updateAvailableBalance(); updateLockedBalance(); + updateReservedOfferBalance(); + updateReservedTradeBalance(); updateReservedBalance(); }); } @@ -107,15 +113,16 @@ public class Balances { BigInteger unlockedBalance = xmrWalletService.getWallet().getUnlockedBalance(0); lockedBalance.set(Coin.valueOf(balance.subtract(unlockedBalance).longValueExact())); } - - private void updateReservedBalance() { - - // add frozen input amounts + + private void updateReservedOfferBalance() { Coin sum = Coin.valueOf(0); List frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false)); for (MoneroOutputWallet frozenOutput : frozenOutputs) sum = sum.add(Coin.valueOf(frozenOutput.getAmount().longValueExact())); - - // add multisig deposit amounts + reservedOfferBalance.set(sum); + } + + private void updateReservedTradeBalance() { + Coin sum = Coin.valueOf(0); List openTrades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList()); for (Trade trade : openTrades) { if (trade.getContract() == null) continue; @@ -128,8 +135,10 @@ public class Balances { } sum = sum.add(Coin.valueOf(ParsingUtils.centinerosToAtomicUnits(reservedAmt).longValueExact())); } - - // set reserved balance - reservedBalance.set(sum); + reservedTradeBalance.set(sum); + } + + private void updateReservedBalance() { + reservedBalance.set(reservedOfferBalance.get().add(reservedTradeBalance.get())); } } diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index e1c641597d..4002f8a1a4 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -606,11 +606,10 @@ message BtcBalanceInfo { } message XmrBalanceInfo { - uint64 balance = 1; - uint64 availableBalance = 2; - uint64 lockedBalance = 3; - uint64 reservedBalance = 4; - uint64 totalBalance = 5; // balance + reserved + uint64 unlockedBalance = 1; + uint64 lockedBalance = 2; + uint64 reservedOfferBalance = 3; + uint64 reservedTradeBalance = 4; } message AddressBalanceInfo {