From 02ac14e234716528b02efbc3017ac2f68a418ac6 Mon Sep 17 00:00:00 2001 From: Christoph Atteneder Date: Tue, 7 Jan 2020 16:28:56 +0100 Subject: [PATCH 1/5] Use trading fee in BSQ fee comparison --- core/src/main/resources/i18n/displayStrings.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index c4c3a4f81a8..fea926a09e4 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -189,7 +189,7 @@ shared.makerTxFee=Maker: {0} shared.takerTxFee=Taker: {0} shared.securityDepositBox.description=Security deposit for BTC {0} shared.iConfirm=I confirm -shared.tradingFeeInBsqInfo=equivalent to {0} used as mining fee +shared.tradingFeeInBsqInfo=equivalent to {0} used as trading fee shared.openURL=Open {0} shared.fiat=Fiat shared.crypto=Crypto From e6f491c8ac8c9541095303dbb4475445836ce5b3 Mon Sep 17 00:00:00 2001 From: Christoph Atteneder Date: Tue, 7 Jan 2020 16:32:24 +0100 Subject: [PATCH 2/5] Add information if minimum trading fee or minimum security deposit is used --- .../resources/i18n/displayStrings.properties | 4 ++- .../main/offer/MutableOfferViewModel.java | 12 +++++-- .../offer/takeoffer/TakeOfferViewModel.java | 14 ++++++-- .../pendingtrades/PendingTradesViewModel.java | 23 ++++++++++-- .../main/java/bisq/desktop/util/GUIUtil.java | 12 +++++-- .../java/bisq/desktop/util/GUIUtilTest.java | 36 +++++++++++++++++++ 6 files changed, 88 insertions(+), 13 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index fea926a09e4..8f3e9e6a0c2 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -170,6 +170,7 @@ shared.viewContractAsJson=View contract in JSON format shared.contract.title=Contract for trade with ID: {0} shared.paymentDetails=BTC {0} payment details shared.securityDeposit=Security deposit +shared.securityDepositLowerCase=security deposit shared.yourSecurityDeposit=Your security deposit shared.contract=Contract shared.messageArrived=Message arrived. @@ -214,6 +215,7 @@ shared.arbitrator=Arbitrator shared.refundAgent=Arbitrator shared.refundAgentForSupportStaff=Refund agent shared.delayedPayoutTxId=Refund collateral transaction ID +shared.tradeFee=trading fee #################################################################### @@ -2738,7 +2740,7 @@ URL: \"{0}\" guiUtil.openWebBrowser.doOpen=Open the web page and don't ask again guiUtil.openWebBrowser.copyUrl=Copy URL and cancel guiUtil.ofTradeAmount=of trade amount - +guiUtil.minValue=minimum {0} is used #################################################################### # Component specific diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index d892b7f2c91..640beb88dd1 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -48,6 +48,7 @@ import bisq.core.offer.OfferRestrictions; import bisq.core.offer.OfferUtil; import bisq.core.payment.PaymentAccount; +import bisq.core.provider.fee.FeeService; import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.PriceFeedService; import bisq.core.user.Preferences; @@ -970,7 +971,10 @@ public String getSecurityDepositPopOverLabel(String depositInBTC) { public String getSecurityDepositInfo() { return btcFormatter.formatCoinWithCode(dataModel.getSecurityDeposit()) + - GUIUtil.getPercentageOfTradeAmount(dataModel.getSecurityDeposit(), dataModel.getAmount().get()); + GUIUtil.getPercentageOfTradeAmount(dataModel.getSecurityDeposit(), + dataModel.getAmount().get(), + Restrictions.getMinBuyerSecurityDepositAsCoin(), + Res.get("shared.securityDepositLowerCase")); } public String getSecurityDepositWithCode() { @@ -982,7 +986,9 @@ public String getTradeFee() { final Coin makerFeeAsCoin = dataModel.getMakerFee(); final String makerFee = getFormatterForMakerFee().formatCoinWithCode(makerFeeAsCoin); if (dataModel.isCurrencyForMakerFeeBtc()) - return makerFee + GUIUtil.getPercentageOfTradeAmount(makerFeeAsCoin, dataModel.getAmount().get()); + return makerFee + GUIUtil.getPercentageOfTradeAmount(makerFeeAsCoin, dataModel.getAmount().get(), + FeeService.getMinMakerFee(dataModel.isCurrencyForMakerFeeBtc()), + Res.get("shared.tradeFee")); else return makerFee + " (" + Res.get("shared.tradingFeeInBsqInfo", btcFormatter.formatCoinWithCode(makerFeeAsCoin)) + ")"; } @@ -1018,7 +1024,7 @@ public String getFundsStructure() { public String getTxFee() { Coin txFeeAsCoin = dataModel.getTxFee(); return btcFormatter.formatCoinWithCode(txFeeAsCoin) + - GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get()); + GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get(), Coin.ZERO, ""); } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java index 55cae99dcd0..80aa57dc7fe 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -29,6 +29,7 @@ import bisq.desktop.util.validation.BtcValidator; import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.btc.wallet.Restrictions; import bisq.core.locale.CurrencyUtil; import bisq.core.locale.Res; import bisq.core.monetary.Price; @@ -39,6 +40,7 @@ import bisq.core.offer.OfferUtil; import bisq.core.payment.PaymentAccount; import bisq.core.payment.payload.PaymentMethod; +import bisq.core.provider.fee.FeeService; import bisq.core.provider.price.PriceFeedService; import bisq.core.trade.Trade; import bisq.core.user.Preferences; @@ -707,7 +709,10 @@ String getTradeAmount() { public String getSecurityDepositInfo() { return btcFormatter.formatCoinWithCode(dataModel.getSecurityDeposit()) + - GUIUtil.getPercentageOfTradeAmount(dataModel.getSecurityDeposit(), dataModel.getAmount().get()); + GUIUtil.getPercentageOfTradeAmount(dataModel.getSecurityDeposit(), + dataModel.getAmount().get(), + Restrictions.getMinBuyerSecurityDepositAsCoin(), + Res.get("shared.securityDepositLowerCase")); } public String getSecurityDepositWithCode() { @@ -719,7 +724,9 @@ public String getTradeFee() { final Coin takerFeeAsCoin = dataModel.getTakerFee(); final String takerFee = getFormatterForTakerFee().formatCoinWithCode(takerFeeAsCoin); if (dataModel.isCurrencyForTakerFeeBtc()) - return takerFee + GUIUtil.getPercentageOfTradeAmount(takerFeeAsCoin, dataModel.getAmount().get()); + return takerFee + GUIUtil.getPercentageOfTradeAmount(takerFeeAsCoin, dataModel.getAmount().get(), + FeeService.getMinTakerFee(dataModel.isCurrencyForTakerFeeBtc()), + Res.get("shared.tradeFee")); else return takerFee + " (" + Res.get("shared.tradingFeeInBsqInfo", btcFormatter.formatCoinWithCode(takerFeeAsCoin)) + ")"; } @@ -743,7 +750,8 @@ public String getTotalToPayInfo() { public String getTxFee() { Coin txFeeAsCoin = dataModel.getTotalTxFee(); return btcFormatter.formatCoinWithCode(txFeeAsCoin) + - GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get()); + GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get(), + Coin.ZERO, ""); } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java index 97b1426a951..b932fa4adbd 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -24,10 +24,12 @@ import bisq.core.account.witness.AccountAgeWitness; import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.btc.wallet.Restrictions; import bisq.core.locale.CurrencyUtil; import bisq.core.locale.Res; import bisq.core.network.MessageState; import bisq.core.offer.Offer; +import bisq.core.provider.fee.FeeService; import bisq.core.trade.Contract; import bisq.core.trade.Trade; import bisq.core.trade.closed.ClosedTradableManager; @@ -291,7 +293,8 @@ public String getFiatVolume() { public String getTxFee() { if (trade != null && trade.getTradeAmount() != null) { Coin txFee = dataModel.getTxFee(); - String percentage = GUIUtil.getPercentageOfTradeAmount(txFee, trade.getTradeAmount()); + String percentage = GUIUtil.getPercentageOfTradeAmount(txFee, trade.getTradeAmount(), + Coin.ZERO, ""); return btcFormatter.formatCoinWithCode(txFee) + percentage; } else { return ""; @@ -303,7 +306,13 @@ public String getTradeFee() { if (dataModel.isMaker() && dataModel.getOffer().isCurrencyForMakerFeeBtc() || !dataModel.isMaker() && dataModel.getTrade().isCurrencyForTakerFeeBtc()) { Coin tradeFeeInBTC = dataModel.getTradeFeeInBTC(); - String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInBTC, trade.getTradeAmount()); + + Coin minTradeFee = dataModel.isMaker() ? + FeeService.getMinMakerFee(true) : + FeeService.getMinTakerFee(true); + + String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInBTC, trade.getTradeAmount(), + minTradeFee, Res.get("shared.tradeFee")); return btcFormatter.formatCoinWithCode(tradeFeeInBTC) + percentage; } else { return bsqFormatter.formatCoinWithCode(dataModel.getTradeFeeAsBsq()); @@ -320,7 +329,15 @@ public String getSecurityDeposit() { Coin securityDeposit = dataModel.isBuyer() ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit(); - String percentage = GUIUtil.getPercentageOfTradeAmount(securityDeposit, trade.getTradeAmount()); + + Coin minSecurityDeposit = dataModel.isBuyer() ? + Restrictions.getMinBuyerSecurityDepositAsCoin() : + Restrictions.getMinSellerSecurityDepositAsCoin(); + + String percentage = GUIUtil.getPercentageOfTradeAmount(securityDeposit, + trade.getTradeAmount(), + minSecurityDeposit, + Res.get("shared.securityDepositLowerCase")); return btcFormatter.formatCoinWithCode(securityDeposit) + percentage; } else { return ""; diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java index 18b55591232..649f6fce0d9 100644 --- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java @@ -49,10 +49,10 @@ import bisq.core.user.DontShowAgainLookup; import bisq.core.user.Preferences; import bisq.core.user.User; +import bisq.core.util.FormattingUtils; import bisq.core.util.coin.BsqFormatter; import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinUtil; -import bisq.core.util.FormattingUtils; import bisq.network.p2p.P2PService; @@ -662,9 +662,15 @@ private static void doOpenWebPage(String target) { } } - public static String getPercentageOfTradeAmount(Coin fee, Coin tradeAmount) { - return " (" + getPercentage(fee, tradeAmount) + + public static String getPercentageOfTradeAmount(Coin fee, Coin tradeAmount, Coin minFee, String feeType) { + String result = " (" + getPercentage(fee, tradeAmount) + " " + Res.get("guiUtil.ofTradeAmount") + ")"; + + if (!fee.isGreaterThan(minFee)) { + result += " - " + Res.get("guiUtil.minValue", feeType); + } + + return result; } public static String getPercentage(Coin part, Coin total) { diff --git a/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java b/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java index f6d19efaa7b..6299b646b0c 100644 --- a/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java +++ b/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java @@ -23,6 +23,9 @@ import bisq.core.user.DontShowAgainLookup; import bisq.core.user.Preferences; +import org.bitcoinj.core.Coin; +import org.bitcoinj.core.CoinMaker; + import javafx.util.StringConverter; import java.util.HashMap; @@ -35,6 +38,11 @@ import static bisq.desktop.maker.TradeCurrencyMakers.bitcoin; import static bisq.desktop.maker.TradeCurrencyMakers.euro; +import static com.natpryce.makeiteasy.MakeItEasy.a; +import static com.natpryce.makeiteasy.MakeItEasy.make; +import static com.natpryce.makeiteasy.MakeItEasy.with; +import static org.bitcoinj.core.CoinMaker.oneBitcoin; +import static org.bitcoinj.core.CoinMaker.satoshis; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -103,4 +111,32 @@ public void testOpenURLWithoutCampaignParameters() throws Exception { assertEquals("https://www.github.com", captor.getValue().toString()); */ } + + @Test + public void percentageOfTradeAmount_higherFeeAsMin() { + + Coin fee = make(a(CoinMaker.Coin).but(with(satoshis, 20000L))); + Coin min = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); + + assertEquals(" (0.02% of trade amount)", GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, min, Res.get("shared.tradeFee"))); + } + + @Test + public void percentageOfTradeAmount_minFee() { + + Coin fee = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); + Coin min = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); + + assertEquals(" (0.01% of trade amount) - minimum trading fee is used", + GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, min, Res.get("shared.tradeFee"))); + } + + @Test + public void percentageOfTradeAmount_minFeeZERO() { + + Coin fee = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); + + assertEquals(" (0.01% of trade amount)", + GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, Coin.ZERO, "")); + } } From d904d1ee6a0038b903077e1472ad6df032d77c28 Mon Sep 17 00:00:00 2001 From: Christoph Atteneder Date: Tue, 7 Jan 2020 17:30:00 +0100 Subject: [PATCH 3/5] Show minimum security deposit in create offer dialog when used In the past we allowed the user to enter a percentage of the trade amount although it wasn't used if the minimum security deposit was higher. --- .../resources/i18n/displayStrings.properties | 1 + .../main/offer/MutableOfferDataModel.java | 4 ++++ .../desktop/main/offer/MutableOfferView.java | 22 ++++++++++++++++--- .../main/offer/MutableOfferViewModel.java | 14 ++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 8f3e9e6a0c2..2398e71e4af 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -481,6 +481,7 @@ createOffer.setDeposit=Set buyer's security deposit (%) createOffer.setDepositAsBuyer=Set my security deposit as buyer (%) createOffer.securityDepositInfo=Your buyer''s security deposit will be {0} createOffer.securityDepositInfoAsBuyer=Your security deposit as buyer will be {0} +createOffer.minSecurityDepositUsed=Min. buyer security deposit is used #################################################################### diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java index 306f2797f85..5cbd272beaa 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferDataModel.java @@ -713,4 +713,8 @@ boolean canPlaceOffer() { return GUIUtil.isBootstrappedOrShowPopup(p2PService) && GUIUtil.canCreateOrTakeOfferOrShowPopup(user, navigation); } + + public boolean isMinBuyerSecurityDeposit() { + return !getBuyerSecurityDepositAsCoin().isGreaterThan(Restrictions.getMinBuyerSecurityDepositAsCoin()); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java index eebc78e1a2d..31529db65f8 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java @@ -144,7 +144,8 @@ public abstract class MutableOfferView> exten private FundsTextField totalToPayTextField; private Label amountDescriptionLabel, priceCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel, waitingForFundsLabel, marketBasedPriceLabel, percentagePriceDescription, tradeFeeDescriptionLabel, - resultLabel, tradeFeeInBtcLabel, tradeFeeInBsqLabel, xLabel, fakeXLabel, buyerSecurityDepositLabel; + resultLabel, tradeFeeInBtcLabel, tradeFeeInBsqLabel, xLabel, fakeXLabel, buyerSecurityDepositLabel, + buyerSecurityDepositPercentageLabel; protected Label amountBtcLabel, volumeCurrencyLabel, minAmountBtcLabel; private ComboBox paymentAccountsComboBox; private ComboBox currencyComboBox; @@ -159,7 +160,8 @@ public abstract class MutableOfferView> exten private ChangeListener amountFocusedListener, minAmountFocusedListener, volumeFocusedListener, buyerSecurityDepositFocusedListener, priceFocusedListener, placeOfferCompletedListener, priceAsPercentageFocusedListener, getShowWalletFundedNotificationListener, - tradeFeeInBtcToggleListener, tradeFeeInBsqToggleListener, tradeFeeVisibleListener; + tradeFeeInBtcToggleListener, tradeFeeInBsqToggleListener, tradeFeeVisibleListener, + isMinBuyerSecurityDepositListener; private ChangeListener tradeCurrencyCodeListener, errorMessageListener, marketPriceMarginListener, volumeListener, buyerSecurityDepositInBTCListener; private ChangeListener marketPriceAvailableListener; @@ -825,6 +827,18 @@ private void createListeners() { tradeFeeInBsqToggle.setVisible(newValue); } }; + + isMinBuyerSecurityDepositListener = ((observable, oldValue, newValue) -> { + if (newValue) { + // show BTC + buyerSecurityDepositPercentageLabel.setText(Res.getBaseCurrencyCode()); + buyerSecurityDepositInputTextField.setDisable(true); + } else { + // show % + buyerSecurityDepositPercentageLabel.setText("%"); + buyerSecurityDepositInputTextField.setDisable(false); + } + }); } private void setIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) { @@ -862,6 +876,7 @@ private void addListeners() { model.volume.addListener(volumeListener); model.isTradeFeeVisible.addListener(tradeFeeVisibleListener); model.buyerSecurityDepositInBTC.addListener(buyerSecurityDepositInBTCListener); + model.isMinBuyerSecurityDeposit.addListener(isMinBuyerSecurityDepositListener); tradeFeeInBtcToggle.selectedProperty().addListener(tradeFeeInBtcToggleListener); tradeFeeInBsqToggle.selectedProperty().addListener(tradeFeeInBsqToggleListener); @@ -897,6 +912,7 @@ private void removeListeners() { model.buyerSecurityDepositInBTC.removeListener(buyerSecurityDepositInBTCListener); tradeFeeInBtcToggle.selectedProperty().removeListener(tradeFeeInBtcToggleListener); tradeFeeInBsqToggle.selectedProperty().removeListener(tradeFeeInBsqToggleListener); + model.isMinBuyerSecurityDeposit.removeListener(isMinBuyerSecurityDepositListener); // focus out amountTextField.focusedProperty().removeListener(amountFocusedListener); @@ -1105,7 +1121,7 @@ private VBox getBuyerSecurityDepositBox() { Res.get("createOffer.securityDeposit.prompt")); buyerSecurityDepositInfoInputTextField = tuple.second; buyerSecurityDepositInputTextField = buyerSecurityDepositInfoInputTextField.getInputTextField(); - Label buyerSecurityDepositPercentageLabel = tuple.third; + buyerSecurityDepositPercentageLabel = tuple.third; // getEditableValueBox delivers BTC, so we overwrite it with % buyerSecurityDepositPercentageLabel.setText("%"); diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index 640beb88dd1..a4f7ed85108 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -148,6 +148,7 @@ public abstract class MutableOfferViewModel ext final BooleanProperty showPayFundsScreenDisplayed = new SimpleBooleanProperty(); private final BooleanProperty showTransactionPublishedScreen = new SimpleBooleanProperty(); final BooleanProperty isWaitingForFunds = new SimpleBooleanProperty(); + final BooleanProperty isMinBuyerSecurityDeposit = new SimpleBooleanProperty(); final ObjectProperty amountValidationResult = new SimpleObjectProperty<>(); final ObjectProperty minAmountValidationResult = new SimpleObjectProperty<>(); @@ -300,6 +301,7 @@ private void createListeners() { dataModel.calculateVolume(); dataModel.calculateTotalToPay(); } + updateBuyerSecurityDeposit(); updateButtonDisableState(); } }; @@ -1202,6 +1204,18 @@ private void updateSpinnerInfo() { isWaitingForFunds.set(!waitingForFundsText.get().isEmpty()); } + private void updateBuyerSecurityDeposit() { + isMinBuyerSecurityDeposit.set(dataModel.isMinBuyerSecurityDeposit()); + + if (dataModel.isMinBuyerSecurityDeposit()) { + buyerSecurityDepositLabel.set(Res.get("createOffer.minSecurityDepositUsed")); + buyerSecurityDeposit.set(btcFormatter.formatCoin(Restrictions.getMinBuyerSecurityDepositAsCoin())); + } else { + buyerSecurityDepositLabel.set(getSecurityDepositLabel()); + buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDeposit().get())); + } + } + private void updateButtonDisableState() { log.debug("updateButtonDisableState"); boolean inputDataValid = isBtcInputValid(amount.get()).isValid && From b9d51caabde244851ac22aa36e92b0d0f87e233a Mon Sep 17 00:00:00 2001 From: Christoph Atteneder Date: Tue, 7 Jan 2020 17:54:47 +0100 Subject: [PATCH 4/5] Only validate security deposit amount if used --- .../java/bisq/desktop/main/offer/MutableOfferViewModel.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index a4f7ed85108..8d1f7a5d0a0 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -1221,13 +1221,17 @@ private void updateButtonDisableState() { boolean inputDataValid = isBtcInputValid(amount.get()).isValid && isBtcInputValid(minAmount.get()).isValid && isPriceInputValid(price.get()).isValid && - securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid && dataModel.getPrice().get() != null && dataModel.getPrice().get().getValue() != 0 && isVolumeInputValid(volume.get()).isValid && isVolumeInputValid(DisplayUtils.formatVolume(dataModel.getMinVolume().get())).isValid && dataModel.isMinAmountLessOrEqualAmount(); + // validating the percentage deposit value only makes sense if it is actually used + if (!dataModel.isMinBuyerSecurityDeposit()) { + inputDataValid = inputDataValid && securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid; + } + isNextButtonDisabled.set(!inputDataValid); // boolean notSufficientFees = dataModel.isWalletFunded.get() && dataModel.isMainNet.get() && !dataModel.isFeeFromFundingTxSufficient.get(); //isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || notSufficientFees); From e7c16a6fe7b58cfc5aed2c9569a274b7e9effe36 Mon Sep 17 00:00:00 2001 From: Christoph Atteneder Date: Tue, 7 Jan 2020 18:20:33 +0100 Subject: [PATCH 5/5] Use general "(required minimum)" label with BTC value if min value is used --- core/src/main/resources/i18n/displayStrings.properties | 4 +--- .../bisq/desktop/main/offer/MutableOfferViewModel.java | 8 +++----- .../desktop/main/offer/takeoffer/TakeOfferViewModel.java | 8 +++----- .../portfolio/pendingtrades/PendingTradesViewModel.java | 7 +++---- desktop/src/main/java/bisq/desktop/util/GUIUtil.java | 4 ++-- desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java | 8 ++++---- 6 files changed, 16 insertions(+), 23 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 2398e71e4af..ca915c4f1e6 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -170,7 +170,6 @@ shared.viewContractAsJson=View contract in JSON format shared.contract.title=Contract for trade with ID: {0} shared.paymentDetails=BTC {0} payment details shared.securityDeposit=Security deposit -shared.securityDepositLowerCase=security deposit shared.yourSecurityDeposit=Your security deposit shared.contract=Contract shared.messageArrived=Message arrived. @@ -215,7 +214,6 @@ shared.arbitrator=Arbitrator shared.refundAgent=Arbitrator shared.refundAgentForSupportStaff=Refund agent shared.delayedPayoutTxId=Refund collateral transaction ID -shared.tradeFee=trading fee #################################################################### @@ -2741,7 +2739,7 @@ URL: \"{0}\" guiUtil.openWebBrowser.doOpen=Open the web page and don't ask again guiUtil.openWebBrowser.copyUrl=Copy URL and cancel guiUtil.ofTradeAmount=of trade amount -guiUtil.minValue=minimum {0} is used +guiUtil.requiredMinimum=(required minimum) #################################################################### # Component specific diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index 8d1f7a5d0a0..cf3aa27dbaf 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -975,8 +975,7 @@ public String getSecurityDepositInfo() { return btcFormatter.formatCoinWithCode(dataModel.getSecurityDeposit()) + GUIUtil.getPercentageOfTradeAmount(dataModel.getSecurityDeposit(), dataModel.getAmount().get(), - Restrictions.getMinBuyerSecurityDepositAsCoin(), - Res.get("shared.securityDepositLowerCase")); + Restrictions.getMinBuyerSecurityDepositAsCoin()); } public String getSecurityDepositWithCode() { @@ -989,8 +988,7 @@ public String getTradeFee() { final String makerFee = getFormatterForMakerFee().formatCoinWithCode(makerFeeAsCoin); if (dataModel.isCurrencyForMakerFeeBtc()) return makerFee + GUIUtil.getPercentageOfTradeAmount(makerFeeAsCoin, dataModel.getAmount().get(), - FeeService.getMinMakerFee(dataModel.isCurrencyForMakerFeeBtc()), - Res.get("shared.tradeFee")); + FeeService.getMinMakerFee(dataModel.isCurrencyForMakerFeeBtc())); else return makerFee + " (" + Res.get("shared.tradingFeeInBsqInfo", btcFormatter.formatCoinWithCode(makerFeeAsCoin)) + ")"; } @@ -1026,7 +1024,7 @@ public String getFundsStructure() { public String getTxFee() { Coin txFeeAsCoin = dataModel.getTxFee(); return btcFormatter.formatCoinWithCode(txFeeAsCoin) + - GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get(), Coin.ZERO, ""); + GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get(), Coin.ZERO); } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java index 80aa57dc7fe..b3f5dfff99f 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -711,8 +711,7 @@ public String getSecurityDepositInfo() { return btcFormatter.formatCoinWithCode(dataModel.getSecurityDeposit()) + GUIUtil.getPercentageOfTradeAmount(dataModel.getSecurityDeposit(), dataModel.getAmount().get(), - Restrictions.getMinBuyerSecurityDepositAsCoin(), - Res.get("shared.securityDepositLowerCase")); + Restrictions.getMinBuyerSecurityDepositAsCoin()); } public String getSecurityDepositWithCode() { @@ -725,8 +724,7 @@ public String getTradeFee() { final String takerFee = getFormatterForTakerFee().formatCoinWithCode(takerFeeAsCoin); if (dataModel.isCurrencyForTakerFeeBtc()) return takerFee + GUIUtil.getPercentageOfTradeAmount(takerFeeAsCoin, dataModel.getAmount().get(), - FeeService.getMinTakerFee(dataModel.isCurrencyForTakerFeeBtc()), - Res.get("shared.tradeFee")); + FeeService.getMinTakerFee(dataModel.isCurrencyForTakerFeeBtc())); else return takerFee + " (" + Res.get("shared.tradingFeeInBsqInfo", btcFormatter.formatCoinWithCode(takerFeeAsCoin)) + ")"; } @@ -751,7 +749,7 @@ public String getTxFee() { Coin txFeeAsCoin = dataModel.getTotalTxFee(); return btcFormatter.formatCoinWithCode(txFeeAsCoin) + GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get(), - Coin.ZERO, ""); + Coin.ZERO); } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java index b932fa4adbd..55e042ea551 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -294,7 +294,7 @@ public String getTxFee() { if (trade != null && trade.getTradeAmount() != null) { Coin txFee = dataModel.getTxFee(); String percentage = GUIUtil.getPercentageOfTradeAmount(txFee, trade.getTradeAmount(), - Coin.ZERO, ""); + Coin.ZERO); return btcFormatter.formatCoinWithCode(txFee) + percentage; } else { return ""; @@ -312,7 +312,7 @@ public String getTradeFee() { FeeService.getMinTakerFee(true); String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInBTC, trade.getTradeAmount(), - minTradeFee, Res.get("shared.tradeFee")); + minTradeFee); return btcFormatter.formatCoinWithCode(tradeFeeInBTC) + percentage; } else { return bsqFormatter.formatCoinWithCode(dataModel.getTradeFeeAsBsq()); @@ -336,8 +336,7 @@ public String getSecurityDeposit() { String percentage = GUIUtil.getPercentageOfTradeAmount(securityDeposit, trade.getTradeAmount(), - minSecurityDeposit, - Res.get("shared.securityDepositLowerCase")); + minSecurityDeposit); return btcFormatter.formatCoinWithCode(securityDeposit) + percentage; } else { return ""; diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java index 649f6fce0d9..1628c7b22b5 100644 --- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java @@ -662,12 +662,12 @@ private static void doOpenWebPage(String target) { } } - public static String getPercentageOfTradeAmount(Coin fee, Coin tradeAmount, Coin minFee, String feeType) { + public static String getPercentageOfTradeAmount(Coin fee, Coin tradeAmount, Coin minFee) { String result = " (" + getPercentage(fee, tradeAmount) + " " + Res.get("guiUtil.ofTradeAmount") + ")"; if (!fee.isGreaterThan(minFee)) { - result += " - " + Res.get("guiUtil.minValue", feeType); + result = " " + Res.get("guiUtil.requiredMinimum"); } return result; diff --git a/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java b/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java index 6299b646b0c..5118f684e2a 100644 --- a/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java +++ b/desktop/src/test/java/bisq/desktop/util/GUIUtilTest.java @@ -118,7 +118,7 @@ public void percentageOfTradeAmount_higherFeeAsMin() { Coin fee = make(a(CoinMaker.Coin).but(with(satoshis, 20000L))); Coin min = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); - assertEquals(" (0.02% of trade amount)", GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, min, Res.get("shared.tradeFee"))); + assertEquals(" (0.02% of trade amount)", GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, min)); } @Test @@ -127,8 +127,8 @@ public void percentageOfTradeAmount_minFee() { Coin fee = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); Coin min = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); - assertEquals(" (0.01% of trade amount) - minimum trading fee is used", - GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, min, Res.get("shared.tradeFee"))); + assertEquals(" (required minimum)", + GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, min)); } @Test @@ -137,6 +137,6 @@ public void percentageOfTradeAmount_minFeeZERO() { Coin fee = make(a(CoinMaker.Coin).but(with(satoshis, 10000L))); assertEquals(" (0.01% of trade amount)", - GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, Coin.ZERO, "")); + GUIUtil.getPercentageOfTradeAmount(fee, oneBitcoin, Coin.ZERO)); } }