balances include unlocked, locked, reserved offers, reserved trades

This commit is contained in:
woodser 2021-09-10 15:41:42 -04:00
parent 58696fe633
commit 59f3fc6385
6 changed files with 73 additions and 70 deletions

View file

@ -38,6 +38,8 @@ class ColumnHeaderConstants {
static final String COL_HEADER_RESERVED_BALANCE = "Reserved Balance"; 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_TOTAL_AVAILABLE_BALANCE = "Total Available Balance";
static final String COL_HEADER_LOCKED_BALANCE = "Locked 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_LOCKED_FOR_VOTING_BALANCE = "Locked For Voting Balance";
static final String COL_HEADER_LOCKUP_BONDS_BALANCE = "Lockup Bonds Balance"; static final String COL_HEADER_LOCKUP_BONDS_BALANCE = "Lockup Bonds Balance";
static final String COL_HEADER_UNLOCKING_BONDS_BALANCE = "Unlocking Bonds Balance"; static final String COL_HEADER_UNLOCKING_BONDS_BALANCE = "Unlocking Bonds Balance";

View file

@ -121,19 +121,19 @@ public class TableFormat {
public static String formatXmrBalanceInfoTbl(XmrBalanceInfo xmrBalanceInfo) { public static String formatXmrBalanceInfoTbl(XmrBalanceInfo xmrBalanceInfo) {
String headerLine = COL_HEADER_BALANCE + COL_HEADER_DELIMITER String headerLine = COL_HEADER_BALANCE + COL_HEADER_DELIMITER
+ COL_HEADER_AVAILABLE_BALANCE + COL_HEADER_DELIMITER + COL_HEADER_AVAILABLE_BALANCE + COL_HEADER_DELIMITER
+ COL_HEADER_RESERVED_BALANCE + COL_HEADER_DELIMITER + COL_HEADER_LOCKED_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_RESERVED_OFFER_BALANCE + COL_HEADER_DELIMITER
+ COL_HEADER_LOCKED_BALANCE + COL_HEADER_DELIMITER + "\n"; + COL_HEADER_RESERVED_TRADE_BALANCE + COL_HEADER_DELIMITER + "\n";
String colDataFormat = "%" + COL_HEADER_BALANCE.length() + "s" // rt justify String colDataFormat = "%" + COL_HEADER_BALANCE.length() + "s" // rt justify
+ " %" + (COL_HEADER_AVAILABLE_BALANCE.length() + 1) + "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_RESERVED_BALANCE.length() + 1) + "s" // rt justify
+ " %" + (COL_HEADER_TOTAL_AVAILABLE_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
return headerLine + format(colDataFormat, return headerLine + format(colDataFormat,
formatSatoshis(xmrBalanceInfo.getAvailableBalance()), formatSatoshis(xmrBalanceInfo.getUnlockedBalance() + xmrBalanceInfo.getLockedBalance()), // total balance
formatSatoshis(xmrBalanceInfo.getReservedBalance()), formatSatoshis(xmrBalanceInfo.getUnlockedBalance()),
formatSatoshis(xmrBalanceInfo.getTotalBalance()), formatSatoshis(xmrBalanceInfo.getReservedOfferBalance()),
formatSatoshis(xmrBalanceInfo.getLockedBalance())); formatSatoshis(xmrBalanceInfo.getReservedTradeBalance()));
} }
public static String formatPaymentAcctTbl(List<PaymentAccount> paymentAccounts) { public static String formatPaymentAcctTbl(List<PaymentAccount> paymentAccounts) {

View file

@ -636,19 +636,22 @@ class CoreWalletsService {
if (availableBalance == null) if (availableBalance == null)
throw new IllegalStateException("available balance is not yet available"); 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(); var lockedBalance = balances.getLockedBalance().get();
if (lockedBalance == null) if (lockedBalance == null)
throw new IllegalStateException("locked balance is not yet available"); throw new IllegalStateException("locked balance is not yet available");
return new XmrBalanceInfo(availableBalance.add(lockedBalance).value, var reservedOfferBalance = balances.getReservedOfferBalance().get();
availableBalance.value, if (reservedOfferBalance == null)
lockedBalance.value, throw new IllegalStateException("reserved offer balance is not yet available");
reservedBalance.value,
availableBalance.add(lockedBalance).add(reservedBalance).value); var reservedTradeBalance = balances.getReservedTradeBalance().get();
if (reservedTradeBalance == null)
throw new IllegalStateException("reserved trade balance is not yet available");
return new XmrBalanceInfo(availableBalance.longValue(),
lockedBalance.longValue(),
reservedOfferBalance.longValue(),
reservedTradeBalance.longValue());
} }
// Returns a Coin for the transfer amount string, or a RuntimeException if invalid. // Returns a Coin for the transfer amount string, or a RuntimeException if invalid.

View file

@ -10,42 +10,35 @@ import lombok.Getter;
public class XmrBalanceInfo implements Payload { public class XmrBalanceInfo implements Payload {
public static final XmrBalanceInfo EMPTY = new XmrBalanceInfo(-1, public static final XmrBalanceInfo EMPTY = new XmrBalanceInfo(-1,
-1,
-1, -1,
-1, -1,
-1); -1);
// All balances are in XMR centineros: https://www.getmonero.org/resources/moneropedia/denominations.html // all balances are in atomic units
private final long balance; private final long unlockedBalance;
private final long availableBalance;
private final long lockedBalance; private final long lockedBalance;
private final long reservedBalance; private final long reservedOfferBalance;
private final long totalBalance; // balance + reserved private final long reservedTradeBalance;
public XmrBalanceInfo(long balance, public XmrBalanceInfo(long unlockedBalance,
long availableBalance,
long lockedBalance, long lockedBalance,
long reservedBalance, long reservedOfferBalance,
long totalBalance) { long reservedTradeBalance) {
this.balance = balance; this.unlockedBalance = unlockedBalance;
this.availableBalance = availableBalance;
this.lockedBalance = lockedBalance; this.lockedBalance = lockedBalance;
this.reservedBalance = reservedBalance; this.reservedOfferBalance = reservedOfferBalance;
this.totalBalance = totalBalance; this.reservedTradeBalance = reservedTradeBalance;
} }
@VisibleForTesting @VisibleForTesting
public static XmrBalanceInfo valueOf(long balance, public static XmrBalanceInfo valueOf(long unlockedBalance,
long availableBalance,
long lockedBalance, long lockedBalance,
long reservedBalance, long reservedOfferBalance,
long totalBalance) { long reservedTradeBalance) {
// Convenience for creating a model instance instead of a proto. return new XmrBalanceInfo(unlockedBalance,
return new XmrBalanceInfo(balance,
availableBalance,
lockedBalance, lockedBalance,
reservedBalance, reservedOfferBalance,
totalBalance); reservedTradeBalance);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -55,30 +48,27 @@ public class XmrBalanceInfo implements Payload {
@Override @Override
public bisq.proto.grpc.XmrBalanceInfo toProtoMessage() { public bisq.proto.grpc.XmrBalanceInfo toProtoMessage() {
return bisq.proto.grpc.XmrBalanceInfo.newBuilder() return bisq.proto.grpc.XmrBalanceInfo.newBuilder()
.setBalance(balance) .setUnlockedBalance(unlockedBalance)
.setAvailableBalance(availableBalance)
.setLockedBalance(lockedBalance) .setLockedBalance(lockedBalance)
.setReservedBalance(reservedBalance) .setReservedOfferBalance(reservedOfferBalance)
.setTotalBalance(totalBalance) .setReservedTradeBalance(reservedTradeBalance)
.build(); .build();
} }
public static XmrBalanceInfo fromProto(bisq.proto.grpc.XmrBalanceInfo proto) { public static XmrBalanceInfo fromProto(bisq.proto.grpc.XmrBalanceInfo proto) {
return new XmrBalanceInfo(proto.getBalance(), return new XmrBalanceInfo(proto.getUnlockedBalance(),
proto.getAvailableBalance(),
proto.getLockedBalance(), proto.getLockedBalance(),
proto.getReservedBalance(), proto.getReservedOfferBalance(),
proto.getTotalBalance()); proto.getReservedTradeBalance());
} }
@Override @Override
public String toString() { public String toString() {
return "BtcBalanceInfo{" + return "BtcBalanceInfo{" +
"balance=" + balance + "unlockedBalance=" + unlockedBalance +
", availableBalance=" + availableBalance +
", lockedBalance=" + lockedBalance + ", lockedBalance=" + lockedBalance +
", reservedBalance=" + reservedBalance + ", reservedOfferBalance=" + reservedOfferBalance +
", totalBalance=" + totalBalance + ", reservedTradeBalance=" + reservedTradeBalance +
'}'; '}';
} }
} }

View file

@ -56,9 +56,13 @@ public class Balances {
@Getter @Getter
private final ObjectProperty<Coin> availableBalance = new SimpleObjectProperty<>(); private final ObjectProperty<Coin> availableBalance = new SimpleObjectProperty<>();
@Getter @Getter
private final ObjectProperty<Coin> reservedBalance = new SimpleObjectProperty<>();
@Getter
private final ObjectProperty<Coin> lockedBalance = new SimpleObjectProperty<>(); private final ObjectProperty<Coin> lockedBalance = new SimpleObjectProperty<>();
@Getter
private final ObjectProperty<Coin> reservedOfferBalance = new SimpleObjectProperty<>();
@Getter
private final ObjectProperty<Coin> reservedTradeBalance = new SimpleObjectProperty<>();
@Getter
private final ObjectProperty<Coin> reservedBalance = new SimpleObjectProperty<>(); // TODO (woodser): this balance is sum of reserved funds for offers and trade multisigs; remove?
@Inject @Inject
public Balances(TradeManager tradeManager, public Balances(TradeManager tradeManager,
@ -92,6 +96,8 @@ public class Balances {
UserThread.execute(() -> { UserThread.execute(() -> {
updateAvailableBalance(); updateAvailableBalance();
updateLockedBalance(); updateLockedBalance();
updateReservedOfferBalance();
updateReservedTradeBalance();
updateReservedBalance(); updateReservedBalance();
}); });
} }
@ -108,14 +114,15 @@ public class Balances {
lockedBalance.set(Coin.valueOf(balance.subtract(unlockedBalance).longValueExact())); lockedBalance.set(Coin.valueOf(balance.subtract(unlockedBalance).longValueExact()));
} }
private void updateReservedBalance() { private void updateReservedOfferBalance() {
// add frozen input amounts
Coin sum = Coin.valueOf(0); Coin sum = Coin.valueOf(0);
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false)); List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
for (MoneroOutputWallet frozenOutput : frozenOutputs) sum = sum.add(Coin.valueOf(frozenOutput.getAmount().longValueExact())); for (MoneroOutputWallet frozenOutput : frozenOutputs) sum = sum.add(Coin.valueOf(frozenOutput.getAmount().longValueExact()));
reservedOfferBalance.set(sum);
}
// add multisig deposit amounts private void updateReservedTradeBalance() {
Coin sum = Coin.valueOf(0);
List<Trade> openTrades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList()); List<Trade> openTrades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList());
for (Trade trade : openTrades) { for (Trade trade : openTrades) {
if (trade.getContract() == null) continue; if (trade.getContract() == null) continue;
@ -128,8 +135,10 @@ public class Balances {
} }
sum = sum.add(Coin.valueOf(ParsingUtils.centinerosToAtomicUnits(reservedAmt).longValueExact())); sum = sum.add(Coin.valueOf(ParsingUtils.centinerosToAtomicUnits(reservedAmt).longValueExact()));
} }
reservedTradeBalance.set(sum);
}
// set reserved balance private void updateReservedBalance() {
reservedBalance.set(sum); reservedBalance.set(reservedOfferBalance.get().add(reservedTradeBalance.get()));
} }
} }

View file

@ -606,11 +606,10 @@ message BtcBalanceInfo {
} }
message XmrBalanceInfo { message XmrBalanceInfo {
uint64 balance = 1; uint64 unlockedBalance = 1;
uint64 availableBalance = 2; uint64 lockedBalance = 2;
uint64 lockedBalance = 3; uint64 reservedOfferBalance = 3;
uint64 reservedBalance = 4; uint64 reservedTradeBalance = 4;
uint64 totalBalance = 5; // balance + reserved
} }
message AddressBalanceInfo { message AddressBalanceInfo {