Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect rounding of BSQ dollar price to whole number #3953

Merged
merged 2 commits into from Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 30 additions & 25 deletions desktop/src/main/java/bisq/desktop/util/DisplayUtils.java
Expand Up @@ -23,6 +23,7 @@
import java.text.DateFormat;

import java.math.BigDecimal;
import java.math.RoundingMode;

import java.util.Date;
import java.util.Optional;
Expand All @@ -31,8 +32,8 @@

@Slf4j
public class DisplayUtils {
private final static int scale = 3;
private static final MonetaryFormat fiatVolumeFormat = new MonetaryFormat().shift(0).minDecimals(0).repeatOptionalDecimals(0, 0);
private static final int SCALE = 3;
private static final MonetaryFormat FIAT_VOLUME_FORMAT = new MonetaryFormat().shift(0).minDecimals(0).repeatOptionalDecimals(0, 0);

public static String formatDateTime(Date date) {
return FormattingUtils.formatDateTime(date, true);
Expand Down Expand Up @@ -96,7 +97,7 @@ public static String formatVolume(Offer offer, Boolean decimalAligned, int maxNu
}

public static String formatVolume(Volume volume) {
return formatVolume(volume, fiatVolumeFormat, false);
return formatVolume(volume, FIAT_VOLUME_FORMAT, false);
}

private static String formatVolume(Volume volume, MonetaryFormat fiatVolumeFormat, boolean appendCurrencyCode) {
Expand All @@ -112,7 +113,11 @@ private static String formatVolume(Volume volume, MonetaryFormat fiatVolumeForma
}

public static String formatVolumeWithCode(Volume volume) {
return formatVolume(volume, fiatVolumeFormat, true);
return formatVolume(volume, FIAT_VOLUME_FORMAT, true);
}

static String formatAverageVolumeWithCode(Volume volume) {
return formatVolume(volume, FIAT_VOLUME_FORMAT.minDecimals(2), true);
}

public static String formatVolumeLabel(String currencyCode) {
Expand Down Expand Up @@ -205,24 +210,20 @@ public static String getOfferDirectionForCreateOffer(OfferPayload.Direction dire
// Amount
///////////////////////////////////////////////////////////////////////////////////////////

public static String formatAmount(Offer offer, CoinFormatter formatter) {
return formatAmount(offer, false, formatter);
}

private static String formatAmount(Offer offer, boolean decimalAligned, CoinFormatter coinFormatter) {
String formattedAmount = offer.isRange() ? coinFormatter.formatCoin(offer.getMinAmount()) + FormattingUtils.RANGE_SEPARATOR + coinFormatter.formatCoin(offer.getAmount()) : coinFormatter.formatCoin(offer.getAmount());
if (decimalAligned) {
formattedAmount = FormattingUtils.fillUpPlacesWithEmptyStrings(formattedAmount, 15);
}
return formattedAmount;
public static String formatAmount(Offer offer, CoinFormatter coinFormatter) {
return offer.isRange()
? coinFormatter.formatCoin(offer.getMinAmount()) + FormattingUtils.RANGE_SEPARATOR + coinFormatter.formatCoin(offer.getAmount())
: coinFormatter.formatCoin(offer.getAmount());
}

public static String formatAmount(Offer offer,
int decimalPlaces,
boolean decimalAligned,
int maxPlaces,
CoinFormatter coinFormatter) {
String formattedAmount = offer.isRange() ? coinFormatter.formatCoin(offer.getMinAmount(), decimalPlaces) + FormattingUtils.RANGE_SEPARATOR + coinFormatter.formatCoin(offer.getAmount(), decimalPlaces) : coinFormatter.formatCoin(offer.getAmount(), decimalPlaces);
String formattedAmount = offer.isRange()
? coinFormatter.formatCoin(offer.getMinAmount(), decimalPlaces) + FormattingUtils.RANGE_SEPARATOR + coinFormatter.formatCoin(offer.getAmount(), decimalPlaces)
: coinFormatter.formatCoin(offer.getAmount(), decimalPlaces);

if (decimalAligned) {
formattedAmount = FormattingUtils.fillUpPlacesWithEmptyStrings(formattedAmount, maxPlaces);
Expand Down Expand Up @@ -258,17 +259,21 @@ public static String getFeeWithFiatAmount(Coin makerFeeAsCoin,

/**
* Converts to a coin with max. 4 decimal places. Last place gets rounded.
* 0.01234 -> 0.0123
* 0.01235 -> 0.0124
* <p>0.01234 -> 0.0123
* <p>0.01235 -> 0.0124
*
* @param input
* @param coinFormatter
* @return
* @param input the decimal coin value to parse and round
* @param coinFormatter the coin formatter instance
* @return the converted coin
*/
public static Coin parseToCoinWith4Decimals(String input, CoinFormatter coinFormatter) {
try {
return Coin.valueOf(new BigDecimal(ParsingUtils.parseToCoin(ParsingUtils.cleanDoubleInput(input), coinFormatter).value).setScale(-scale - 1,
BigDecimal.ROUND_HALF_UP).setScale(scale + 1, BigDecimal.ROUND_HALF_UP).toBigInteger().longValue());
return Coin.valueOf(
new BigDecimal(ParsingUtils.parseToCoin(ParsingUtils.cleanDoubleInput(input), coinFormatter).value)
.setScale(-SCALE - 1, RoundingMode.HALF_UP)
.setScale(SCALE + 1, RoundingMode.HALF_UP)
.toBigInteger().longValue()
);
} catch (Throwable t) {
if (input != null && input.length() > 0)
log.warn("Exception at parseToCoinWith4Decimals: " + t.toString());
Expand All @@ -283,9 +288,9 @@ public static boolean hasBtcValidDecimals(String input, CoinFormatter coinFormat
/**
* Transform a coin with the properties defined in the format (used to reduce decimal places)
*
* @param coin The coin which should be transformed
* @param coinFormatter
* @return The transformed coin
* @param coin the coin which should be transformed
* @param coinFormatter the coin formatter instance
* @return the transformed coin
*/
public static Coin reduceTo4Decimals(Coin coin, CoinFormatter coinFormatter) {
return ParsingUtils.parseToCoin(coinFormatter.formatCoin(coin), coinFormatter);
Expand Down
4 changes: 2 additions & 2 deletions desktop/src/main/java/bisq/desktop/util/GUIUtil.java
Expand Up @@ -949,7 +949,7 @@ public static void showBsqFeeInfoPopup(Coin fee, Coin miningFee, int txSize, Bsq
showBsqFeeInfoPopup(fee, miningFee, null, txSize, bsqFormatter, btcFormatter, type, actionHandler);
}

public static void setFitToRowsForTableView(TableView tableView,
public static void setFitToRowsForTableView(TableView<?> tableView,
int rowHeight,
int headerHeight,
int minNumRows,
Expand Down Expand Up @@ -1100,7 +1100,7 @@ public static String getBsqInUsd(Price bsqPrice,
Volume bsqAmountAsVolume = Volume.parse(bsqAmountAsString, "BSQ");
Coin requiredBtc = bsqPrice.getAmountByVolume(bsqAmountAsVolume);
Volume volumeByAmount = usdPrice.getVolumeByAmount(requiredBtc);
return DisplayUtils.formatVolumeWithCode(volumeByAmount);
return DisplayUtils.formatAverageVolumeWithCode(volumeByAmount);
}

public static MaterialDesignIcon getIconForSignState(AccountAgeWitnessService.SignState state) {
Expand Down
23 changes: 19 additions & 4 deletions desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java
Expand Up @@ -22,8 +22,12 @@
import bisq.core.locale.GlobalSettings;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
import bisq.core.monetary.Price;
import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.user.DontShowAgainLookup;
import bisq.core.user.Preferences;
import bisq.core.util.coin.BsqFormatter;

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.CoinMaker;
Expand Down Expand Up @@ -51,7 +55,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


@Ignore
public class GUIUtilTest {

Expand All @@ -65,7 +68,7 @@ public void setup() {

@Test
public void testTradeCurrencyConverter() {
Map<String, Integer> offerCounts = new HashMap<String, Integer>() {{
Map<String, Integer> offerCounts = new HashMap<>() {{
put("BTC", 11);
put("EUR", 10);
}};
Expand All @@ -80,7 +83,7 @@ public void testTradeCurrencyConverter() {
}

@Test
public void testOpenURLWithCampaignParameters() throws Exception {
public void testOpenURLWithCampaignParameters() {
Preferences preferences = mock(Preferences.class);
DontShowAgainLookup.setPreferences(preferences);
GUIUtil.setPreferences(preferences);
Expand All @@ -101,7 +104,7 @@ public void testOpenURLWithCampaignParameters() throws Exception {
}

@Test
public void testOpenURLWithoutCampaignParameters() throws Exception {
public void testOpenURLWithoutCampaignParameters() {
Preferences preferences = mock(Preferences.class);
DontShowAgainLookup.setPreferences(preferences);
GUIUtil.setPreferences(preferences);
Expand Down Expand Up @@ -143,6 +146,18 @@ public void testAddressRegexValidator() {
assertFalse(regexValidator.validate("12.34.56.78:").isValid);
}

@Test
public void testGetBsqInUsd() {
PriceFeedService priceFeedService = mock(PriceFeedService.class);
when(priceFeedService.getMarketPrice("USD"))
.thenReturn(new MarketPrice("USD", 12345.6789, 0, true));

Coin oneBsq = Coin.valueOf(100);
Price avgPrice = Price.valueOf("BSQ", 10000);

assertEquals("1.23 USD", GUIUtil.getBsqInUsd(avgPrice, oneBsq, priceFeedService, new BsqFormatter()));
}

@Test
public void percentageOfTradeAmount_higherFeeAsMin() {

Expand Down