Skip to content

Commit

Permalink
Adjust cli to TradeInfo .proto's price & volume type change
Browse files Browse the repository at this point in the history
Quite a bit of refactoring.  A lot of number-string formatting was removed.
  • Loading branch information
ghubstan committed Feb 19, 2022
1 parent a0b68bc commit e49ab16
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 360 deletions.
28 changes: 4 additions & 24 deletions cli/src/main/java/bisq/cli/CliMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@
import java.io.PrintStream;
import java.io.PrintWriter;

import java.math.BigDecimal;

import java.util.Date;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import static bisq.cli.CurrencyFormat.*;
import static bisq.cli.CurrencyFormat.formatInternalFiatPrice;
import static bisq.cli.CurrencyFormat.formatTxFeeRateInfo;
import static bisq.cli.CurrencyFormat.toSatoshis;
import static bisq.cli.CurrencyFormat.toSecurityDepositAsPct;
import static bisq.cli.Method.*;
import static bisq.cli.opts.OptLabel.*;
import static bisq.cli.table.builder.TableType.*;
Expand All @@ -53,7 +54,6 @@
import static java.lang.System.err;
import static java.lang.System.exit;
import static java.lang.System.out;
import static java.math.BigDecimal.ZERO;



Expand Down Expand Up @@ -789,26 +789,6 @@ private static long toLong(String param) {
}
}

@Deprecated
private static long toInternalTriggerPrice(GrpcClient client,
String offerId,
BigDecimal unscaledTriggerPrice) {
if (unscaledTriggerPrice.compareTo(ZERO) >= 0) {
// Unfortunately, the EditOffer proto triggerPrice field was declared as
// a long instead of a string, so the CLI has to look at the offer to know
// how to scale the trigger-price (for a fiat or altcoin offer) param sent
// to the server in its 'editoffer' request. That means a preliminary round
// trip to the server: a 'getmyoffer' request.
var offer = client.getOffer(offerId);
if (offer.getCounterCurrencyCode().equals("BTC"))
return toInternalCryptoCurrencyPrice(unscaledTriggerPrice);
else
return toInternalFiatPrice(unscaledTriggerPrice);
} else {
return 0L;
}
}

private static File saveFileToDisk(String prefix,
@SuppressWarnings("SameParameterValue") String suffix,
String text) {
Expand Down
65 changes: 13 additions & 52 deletions cli/src/main/java/bisq/cli/CurrencyFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@
import static java.math.RoundingMode.HALF_UP;
import static java.math.RoundingMode.UNNECESSARY;

/**
* Utility for formatting amounts, volumes and fees; there is no i18n support in the CLI.
*/
@VisibleForTesting
public class CurrencyFormat {

// Use the US locale for all DecimalFormat objects.
// Use the US locale as a base for all DecimalFormats, but commas should be omitted from number strings.
private static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = DecimalFormatSymbols.getInstance(Locale.US);

// Format all numbers displayed in the CLI console with the US locale (no i18n support for CLI).
// Use the US locale as a base for all NumberFormats, but commas should be omitted from number strings.
private static final NumberFormat US_LOCALE_NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);

// Formats numbers for internal use, i.e., grpc request parameters.
Expand All @@ -53,38 +56,26 @@ public class CurrencyFormat {
static final BigDecimal BSQ_SATOSHI_DIVISOR = new BigDecimal(100);
static final DecimalFormat BSQ_FORMAT = new DecimalFormat("###,###,###,##0.00", DECIMAL_FORMAT_SYMBOLS);

static final DecimalFormat ALTCOIN_VOLUME_FORMAT = new DecimalFormat("########0.00", DECIMAL_FORMAT_SYMBOLS);
static final DecimalFormat FIAT_VOLUME_FORMAT = new DecimalFormat("###########0", DECIMAL_FORMAT_SYMBOLS);

static final BigDecimal SECURITY_DEPOSIT_MULTIPLICAND = new BigDecimal("0.01");

public static String formatSatoshis(String sats) {
//noinspection BigDecimalMethodWithoutRoundingCalled
return SATOSHI_FORMAT.format(new BigDecimal(sats).divide(SATOSHI_DIVISOR));
}

@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
public static String formatSatoshis(long sats) {
return SATOSHI_FORMAT.format(BigDecimal.valueOf(sats).divide(SATOSHI_DIVISOR));
return SATOSHI_FORMAT.format(new BigDecimal(sats).divide(SATOSHI_DIVISOR));
}

@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
public static String formatBtc(long sats) {
return BTC_FORMAT.format(BigDecimal.valueOf(sats).divide(SATOSHI_DIVISOR));
return BTC_FORMAT.format(new BigDecimal(sats).divide(SATOSHI_DIVISOR));
}

@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
public static String formatBsq(long sats) {
return BSQ_FORMAT.format(BigDecimal.valueOf(sats).divide(BSQ_SATOSHI_DIVISOR));
}

public static String formatVolumeString(String volumeString, int precision) {
if (volumeString == null || volumeString.isBlank())
return "";

US_LOCALE_NUMBER_FORMAT.setMinimumFractionDigits(precision);
US_LOCALE_NUMBER_FORMAT.setMaximumFractionDigits(precision);
US_LOCALE_NUMBER_FORMAT.setRoundingMode(HALF_UP);
var volAsDouble = new BigDecimal(volumeString).doubleValue();
if (precision == 0)
return FIAT_VOLUME_FORMAT.format(volAsDouble);
else
return ALTCOIN_VOLUME_FORMAT.format(volAsDouble);
return BSQ_FORMAT.format(new BigDecimal(sats).divide(BSQ_SATOSHI_DIVISOR));
}

public static String formatTxFeeRateInfo(TxFeeRateInfo txFeeRateInfo) {
Expand All @@ -111,50 +102,20 @@ public static String formatInternalFiatPrice(double price) {
return US_LOCALE_NUMBER_FORMAT.format(price);
}

@Deprecated
public static String formatPrice(long price) {
US_LOCALE_NUMBER_FORMAT.setMinimumFractionDigits(4);
US_LOCALE_NUMBER_FORMAT.setMaximumFractionDigits(4);
US_LOCALE_NUMBER_FORMAT.setRoundingMode(UNNECESSARY);
return US_LOCALE_NUMBER_FORMAT.format((double) price / 10_000);
}

public static String formatCryptoCurrencyPrice(long price) {
US_LOCALE_NUMBER_FORMAT.setMinimumFractionDigits(8);
US_LOCALE_NUMBER_FORMAT.setMaximumFractionDigits(8);
US_LOCALE_NUMBER_FORMAT.setRoundingMode(UNNECESSARY);
return US_LOCALE_NUMBER_FORMAT.format((double) price / SATOSHI_DIVISOR.doubleValue());
}

public static String formatFiatVolume(long volume) {
US_LOCALE_NUMBER_FORMAT.setMinimumFractionDigits(0);
US_LOCALE_NUMBER_FORMAT.setMaximumFractionDigits(0);
US_LOCALE_NUMBER_FORMAT.setRoundingMode(HALF_UP);
return US_LOCALE_NUMBER_FORMAT.format((double) volume / 10_000);
}

public static String formatCryptoCurrencyVolume(long volume) {
int defaultPrecision = 2;
return formatCryptoCurrencyVolume(volume, defaultPrecision);
}

public static String formatCryptoCurrencyVolume(long volume, int precision) {
US_LOCALE_NUMBER_FORMAT.setMinimumFractionDigits(precision);
US_LOCALE_NUMBER_FORMAT.setMaximumFractionDigits(precision);
US_LOCALE_NUMBER_FORMAT.setRoundingMode(HALF_UP);
return US_LOCALE_NUMBER_FORMAT.format((double) volume / SATOSHI_DIVISOR.doubleValue());
}

@Deprecated
public static long toInternalFiatPrice(BigDecimal fiatPrice) {
return fiatPrice.multiply(new BigDecimal(10_000)).longValue();
}

@Deprecated
public static long toInternalCryptoCurrencyPrice(BigDecimal altcoinPrice) {
return altcoinPrice.multiply(new BigDecimal(100_000_000)).longValue();
}

public static long toSatoshis(String btc) {
if (btc.startsWith("-"))
throw new IllegalArgumentException(format("'%s' is not a positive number", btc));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,3 @@ abstract class AbstractTableBuilder {

public abstract Table build();
}

/*
var currencyCode = isFiatOffer.test(o);
*/
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

import javax.annotation.Nullable;

import static bisq.cli.CurrencyFormat.formatSatoshis;
import static bisq.cli.table.builder.TableBuilderConstants.COL_HEADER_BUYER_DEPOSIT;
import static bisq.cli.table.builder.TableBuilderConstants.COL_HEADER_SELLER_DEPOSIT;
import static bisq.cli.table.builder.TableType.TRADE_DETAIL_TBL;
Expand All @@ -42,7 +43,6 @@

import bisq.cli.table.column.Column;
import bisq.cli.table.column.MixedTradeFeeColumn;
import bisq.cli.table.column.MixedVolumeColumn;

abstract class AbstractTradeListBuilder extends AbstractTableBuilder {

Expand All @@ -55,15 +55,15 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
protected final Column<Long> colCreateDate;
@Nullable
protected final Column<String> colMarket;
protected final Column<Long> colPrice;
protected final Column<String> colPrice;
@Nullable
protected final Column<String> colPriceDeviation;
@Nullable
protected final Column<String> colCurrency;
@Nullable
protected final Column<Long> colAmountInBtc;
protected final Column<Long> colAmount;
@Nullable
protected final MixedVolumeColumn colMixedAmount;
protected final Column<String> colMixedAmount;
@Nullable
protected final Column<Long> colMinerTxFee;
@Nullable
Expand Down Expand Up @@ -94,7 +94,8 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
@Nullable
protected final Column<Long> colBisqTradeFee;
@Nullable
protected final Column<Long> colTradeCost;
protected final Column<String> colTradeCost;
//protected final Column<Long> colTradeCost;
@Nullable
protected final Column<Boolean> colIsPaymentSent;
@Nullable
Expand Down Expand Up @@ -124,7 +125,7 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
this.colPrice = colSupplier.priceColumn.get();
this.colPriceDeviation = colSupplier.priceDeviationColumn.get();
this.colCurrency = colSupplier.currencyColumn.get();
this.colAmountInBtc = colSupplier.amountInBtcColumn.get();
this.colAmount = colSupplier.amountColumn.get();
this.colMixedAmount = colSupplier.mixedAmountColumn.get();
this.colMinerTxFee = colSupplier.minerTxFeeColumn.get();
this.colMixedTradeFee = colSupplier.mixedTradeFeeColumn.get();
Expand All @@ -145,6 +146,7 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
this.colTradeCost = colSupplier.tradeCostColumn.get();
this.colIsPaymentSent = colSupplier.paymentSentColumn.get();
this.colIsPaymentReceived = colSupplier.paymentReceivedColumn.get();
//noinspection ConstantConditions
this.colAltcoinReceiveAddressColumn = colSupplier.altcoinReceiveAddressColumn.get();

// BSQ swap trade detail specific columns
Expand All @@ -167,6 +169,7 @@ protected void validate() {

private final Supplier<Boolean> isTradeDetailTblBuilder = () -> tableType.equals(TRADE_DETAIL_TBL);
protected final Predicate<TradeInfo> isFiatTrade = (t) -> isFiatOffer.test(t.getOffer());
protected final Predicate<TradeInfo> isBsqTrade = (t) -> !isFiatOffer.test(t.getOffer()) && t.getOffer().getBaseCurrencyCode().equals("BSQ");
protected final Predicate<TradeInfo> isBsqSwapTrade = (t) -> t.getOffer().getIsBsqSwapOffer();
protected final Predicate<TradeInfo> isMyOffer = (t) -> t.getOffer().getIsMyOffer();
protected final Predicate<TradeInfo> isTaker = (t) -> t.getRole().toLowerCase().contains("taker");
Expand All @@ -180,15 +183,28 @@ protected void validate() {

// Column Value Functions

protected final Function<TradeInfo, Long> toAmount = (t) ->
isFiatTrade.test(t)
? t.getTradeAmountAsLong()
: t.getTradeVolume();
// Altcoin volumes from server are string representations of decimals.
// Converting them to longs ("sats") requires shifting the decimal points
// to left: 2 for BSQ, 8 for other altcoins.
protected final Function<TradeInfo, Long> toAltcoinTradeVolumeAsLong = (t) ->
isBsqTrade.test(t)
? new BigDecimal(t.getTradeVolume()).movePointRight(2).longValue()
: new BigDecimal(t.getTradeVolume()).movePointRight(8).longValue();

protected final Function<TradeInfo, Long> toTradeVolume = (t) ->
protected final Function<TradeInfo, String> toTradeVolumeAsString = (t) ->
isFiatTrade.test(t)
? t.getTradeVolume()
: t.getTradeAmountAsLong();
: formatSatoshis(t.getTradeAmountAsLong());

protected final Function<TradeInfo, Long> toTradeVolumeAsLong = (t) ->
isFiatTrade.test(t)
? Long.parseLong(t.getTradeVolume())
: toAltcoinTradeVolumeAsLong.apply(t);

protected final Function<TradeInfo, Long> toTradeAmount = (t) ->
isFiatTrade.test(t)
? t.getTradeAmountAsLong()
: toTradeVolumeAsLong.apply(t);

protected final Function<TradeInfo, String> toMarket = (t) ->
t.getOffer().getBaseCurrencyCode() + "/"
Expand All @@ -199,16 +215,6 @@ protected void validate() {
? t.getOffer().getCounterCurrencyCode()
: t.getOffer().getBaseCurrencyCode();


protected final Function<TradeInfo, Integer> toDisplayedVolumePrecision = (t) -> {
if (isFiatTrade.test(t)) {
return 0;
} else {
String currencyCode = toPaymentCurrencyCode.apply(t);
return currencyCode.equalsIgnoreCase("BSQ") ? 2 : 8;
}
};

protected final Function<TradeInfo, String> toPriceDeviation = (t) ->
t.getOffer().getUseMarketBasedPrice()
? formatToPercent(t.getOffer().getMarketPriceMargin())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@


import bisq.cli.table.Table;
import bisq.cli.table.column.MixedPriceColumn;

@SuppressWarnings("ConstantConditions")
class ClosedTradeTableBuilder extends AbstractTradeListBuilder {

ClosedTradeTableBuilder(List<?> protos) {
Expand All @@ -37,10 +37,10 @@ public Table build() {
return new Table(colTradeId,
colCreateDate.asStringColumn(),
colMarket,
colPrice.asStringColumn(),
colPrice.justify(),
colPriceDeviation.justify(),
colAmountInBtc.asStringColumn(),
colMixedAmount.asStringColumn(),
colAmount.asStringColumn(),
colMixedAmount.justify(),
colCurrency,
colMinerTxFee.asStringColumn(),
colMixedTradeFee.asStringColumn(),
Expand All @@ -51,14 +51,14 @@ public Table build() {
}

private void populateColumns() {
trades.stream().forEachOrdered(t -> {
trades.forEach(t -> {
colTradeId.addRow(t.getTradeId());
colCreateDate.addRow(t.getDate());
colMarket.addRow(toMarket.apply(t));
((MixedPriceColumn) colPrice).addRow(t.getTradePrice(), isFiatTrade.test(t));
colPrice.addRow(t.getTradePrice());
colPriceDeviation.addRow(toPriceDeviation.apply(t));
colAmountInBtc.addRow(t.getTradeAmountAsLong());
colMixedAmount.addRow(t.getTradeVolume(), toDisplayedVolumePrecision.apply(t));
colAmount.addRow(t.getTradeAmountAsLong());
colMixedAmount.addRow(t.getTradeVolume());
colCurrency.addRow(toPaymentCurrencyCode.apply(t));
colMinerTxFee.addRow(toMyMinerTxFee.apply(t));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@


import bisq.cli.table.Table;
import bisq.cli.table.column.MixedPriceColumn;

/**
* Builds a {@code bisq.cli.table.Table} from a list of {@code bisq.proto.grpc.TradeInfo} objects.
*/
@SuppressWarnings("ConstantConditions")
class FailedTradeTableBuilder extends AbstractTradeListBuilder {

FailedTradeTableBuilder(List<?> protos) {
Expand All @@ -40,23 +40,23 @@ public Table build() {
return new Table(colTradeId,
colCreateDate.asStringColumn(),
colMarket,
colPrice.asStringColumn(),
colAmountInBtc.asStringColumn(),
colMixedAmount.asStringColumn(),
colPrice.justify(),
colAmount.asStringColumn(),
colMixedAmount.justify(),
colCurrency,
colOfferType,
colRole,
colClosingStatus);
}

private void populateColumns() {
trades.stream().forEachOrdered(t -> {
trades.forEach(t -> {
colTradeId.addRow(t.getTradeId());
colCreateDate.addRow(t.getDate());
colMarket.addRow(toMarket.apply(t));
((MixedPriceColumn) colPrice).addRow(t.getTradePrice(), isFiatTrade.test(t));
colAmountInBtc.addRow(t.getTradeAmountAsLong());
colMixedAmount.addRow(t.getTradeVolume(), toDisplayedVolumePrecision.apply(t));
colPrice.addRow(t.getTradePrice());
colAmount.addRow(t.getTradeAmountAsLong());
colMixedAmount.addRow(t.getTradeVolume());
colCurrency.addRow(toPaymentCurrencyCode.apply(t));
colOfferType.addRow(toOfferType.apply(t));
colRole.addRow(t.getRole());
Expand Down
Loading

0 comments on commit e49ab16

Please sign in to comment.