diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties
index fdda850d637..52e492a6165 100644
--- a/core/src/main/resources/i18n/displayStrings.properties
+++ b/core/src/main/resources/i18n/displayStrings.properties
@@ -192,7 +192,7 @@ shared.tradeWalletBalance=Trade wallet balance
shared.makerTxFee=Maker: {0}
shared.takerTxFee=Taker: {0}
shared.iConfirm=I confirm
-shared.tradingFeeInBsqInfo=equivalent to {0} used as trading fee
+shared.tradingFeeInBsqInfo=≈ {0}
shared.openURL=Open {0}
shared.fiat=Fiat
shared.crypto=Crypto
@@ -454,7 +454,6 @@ createOffer.warning.sellBelowMarketPrice=You will always get {0}% less than the
createOffer.warning.buyAboveMarketPrice=You will always pay {0}% more than the current market price as the price of your offer will be continuously updated.
createOffer.tradeFee.descriptionBTCOnly=Trade fee
createOffer.tradeFee.descriptionBSQEnabled=Select trade fee currency
-createOffer.tradeFee.fiatAndPercent=≈ {0} / {1} of trade amount
# new entries
createOffer.placeOfferButton=Review: Place offer to {0} bitcoin
@@ -462,7 +461,14 @@ createOffer.alreadyFunded=You had already funded that offer.\nYour funds have be
createOffer.createOfferFundWalletInfo.headline=Fund your offer
# suppress inspection "TrailingSpacesInProperty"
createOffer.createOfferFundWalletInfo.tradeAmount=- Trade amount: {0} \n
-createOffer.createOfferFundWalletInfo.msg=You need to deposit {0} to this offer.\n\nThose funds are reserved in your local wallet and will get locked into the multisig deposit address once someone takes your offer.\n\nThe amount is the sum of:\n{1}- Your security deposit: {2}\n- Trading fee: {3}\n- Mining fee: {4}\n\nYou can choose between two options when funding your trade:\n- Use your Bisq wallet (convenient, but transactions may be linkable) OR\n- Transfer from an external wallet (potentially more private)\n\nYou will see all funding options and details after closing this popup.
+createOffer.createOfferFundWalletInfo.msg=You need to deposit {0} to this offer.\n\n\
+ Those funds are reserved in your local wallet and will get locked into the multisig deposit address once someone takes your offer.\n\n\
+ The amount is the sum of:\n\
+ {1}\
+ - Your security deposit: {2}\n\
+ - Trading fee: {3}\n\
+ - Mining fee: {4}\n\n\
+ You can choose between two options when funding your trade:\n- Use your Bisq wallet (convenient, but transactions may be linkable) OR\n- Transfer from an external wallet (potentially more private)\n\nYou will see all funding options and details after closing this popup.
# only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!)
createOffer.amountPriceBox.error.message=An error occurred when placing the offer:\n\n{0}\n\n\
@@ -2702,6 +2708,8 @@ feeOptionWindow.info=You can choose to pay the trade fee in BSQ or in BTC. If yo
feeOptionWindow.optionsLabel=Choose currency for trade fee payment
feeOptionWindow.useBTC=Use BTC
feeOptionWindow.fee={0} (≈ {1})
+feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2})
+feeOptionWindow.btcFeeWithPercentage={0} ({1})
####################################################################
diff --git a/desktop/src/main/java/bisq/desktop/main/offer/FeeUtil.java b/desktop/src/main/java/bisq/desktop/main/offer/FeeUtil.java
new file mode 100644
index 00000000000..82f2363e5ed
--- /dev/null
+++ b/desktop/src/main/java/bisq/desktop/main/offer/FeeUtil.java
@@ -0,0 +1,82 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.desktop.main.offer;
+
+import bisq.desktop.util.DisplayUtils;
+import bisq.desktop.util.GUIUtil;
+
+import bisq.core.locale.Res;
+import bisq.core.monetary.Volume;
+import bisq.core.offer.OfferUtil;
+import bisq.core.util.coin.CoinFormatter;
+
+import bisq.common.app.DevEnv;
+
+import org.bitcoinj.core.Coin;
+
+import java.util.Optional;
+
+public class FeeUtil {
+ public static String getTradeFeeWithFiatEquivalent(OfferUtil offerUtil,
+ Coin tradeFee,
+ boolean isCurrencyForMakerFeeBtc,
+ CoinFormatter formatter) {
+ if (!isCurrencyForMakerFeeBtc && !DevEnv.isDaoActivated()) {
+ return "";
+ }
+
+ Optional optionalBtcFeeInFiat = offerUtil.getFeeInUserFiatCurrency(tradeFee,
+ isCurrencyForMakerFeeBtc,
+ formatter);
+
+ return DisplayUtils.getFeeWithFiatAmount(tradeFee, optionalBtcFeeInFiat, formatter);
+ }
+
+ public static String getTradeFeeWithFiatEquivalentAndPercentage(OfferUtil offerUtil,
+ Coin tradeFee,
+ Coin tradeAmount,
+ boolean isCurrencyForMakerFeeBtc,
+ CoinFormatter formatter,
+ Coin minTradeFee) {
+ if (isCurrencyForMakerFeeBtc) {
+ String feeAsBtc = formatter.formatCoinWithCode(tradeFee);
+ String percentage;
+ if (!tradeFee.isGreaterThan(minTradeFee)) {
+ percentage = Res.get("guiUtil.requiredMinimum")
+ .replace("(", "")
+ .replace(")", "");
+ } else {
+ percentage = GUIUtil.getPercentage(tradeFee, tradeAmount) +
+ " " + Res.get("guiUtil.ofTradeAmount");
+ }
+ return offerUtil.getFeeInUserFiatCurrency(tradeFee,
+ isCurrencyForMakerFeeBtc,
+ formatter)
+ .map(DisplayUtils::formatAverageVolumeWithCode)
+ .map(feeInFiat -> Res.get("feeOptionWindow.btcFeeWithFiatAndPercentage", feeAsBtc, feeInFiat, percentage))
+ .orElseGet(() -> Res.get("feeOptionWindow.btcFeeWithPercentage", feeAsBtc, percentage));
+ } else {
+ // For BSQ we use the fiat equivalent only. Calculating the % value would be more effort.
+ // We could calculate the BTC value if the BSQ fee and use that...
+ return FeeUtil.getTradeFeeWithFiatEquivalent(offerUtil,
+ tradeFee,
+ false,
+ formatter);
+ }
+ }
+}
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 83bd3d9f741..0b0566988b1 100644
--- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java
+++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java
@@ -87,11 +87,13 @@
import javafx.util.Callback;
-import java.util.Optional;
import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+
import static javafx.beans.binding.Bindings.createStringBinding;
+@Slf4j
public abstract class MutableOfferViewModel extends ActivatableWithDataModel {
private final BtcValidator btcValidator;
private final BsqValidator bsqValidator;
@@ -489,55 +491,28 @@ private void createListeners() {
}
private void applyMakerFee() {
- Coin makerFeeAsCoin = dataModel.getMakerFee();
- if (makerFeeAsCoin != null) {
- isTradeFeeVisible.setValue(true);
-
- tradeFee.set(getFormatterForMakerFee().formatCoin(makerFeeAsCoin));
-
- Coin makerFeeInBtc = dataModel.getMakerFeeInBtc();
- Optional optionalBtcFeeInFiat = offerUtil.getFeeInUserFiatCurrency(makerFeeInBtc,
- true,
- bsqFormatter);
- String btcFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBtc, optionalBtcFeeInFiat, btcFormatter);
- if (DevEnv.isDaoActivated()) {
- tradeFeeInBtcWithFiat.set(btcFeeWithFiatAmount);
- } else {
- tradeFeeInBtcWithFiat.set(btcFormatter.formatCoinWithCode(makerFeeAsCoin));
- }
-
- Coin makerFeeInBsq = dataModel.getMakerFeeInBsq();
- Optional optionalBsqFeeInFiat = offerUtil.getFeeInUserFiatCurrency(makerFeeInBsq,
- false,
- bsqFormatter);
- String bsqFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBsq,
- optionalBsqFeeInFiat,
- bsqFormatter);
- if (DevEnv.isDaoActivated()) {
- tradeFeeInBsqWithFiat.set(bsqFeeWithFiatAmount);
- } else {
- // Before DAO is enabled we show fee as fiat and % in second line
- String feeInFiatAsString;
- if (optionalBtcFeeInFiat != null && optionalBtcFeeInFiat.isPresent()) {
- feeInFiatAsString = DisplayUtils.formatVolumeWithCode(optionalBtcFeeInFiat.get());
- } else {
- feeInFiatAsString = Res.get("shared.na");
- }
-
- double amountAsDouble = (double) dataModel.getAmount().get().value;
- double makerFeeInBtcAsDouble = (double) makerFeeInBtc.value;
- double percent = makerFeeInBtcAsDouble / amountAsDouble;
-
- tradeFeeInBsqWithFiat.set(Res.get("createOffer.tradeFee.fiatAndPercent",
- feeInFiatAsString,
- FormattingUtils.formatToPercentWithSymbol(percent)));
- }
- }
tradeFeeCurrencyCode.set(dataModel.isCurrencyForMakerFeeBtc() ? Res.getBaseCurrencyCode() : "BSQ");
tradeFeeDescription.set(DevEnv.isDaoActivated() ? Res.get("createOffer.tradeFee.descriptionBSQEnabled") :
Res.get("createOffer.tradeFee.descriptionBTCOnly"));
+
+ Coin makerFeeAsCoin = dataModel.getMakerFee();
+ if (makerFeeAsCoin == null) {
+ return;
+ }
+
+ isTradeFeeVisible.setValue(true);
+ tradeFee.set(getFormatterForMakerFee().formatCoin(makerFeeAsCoin));
+ tradeFeeInBtcWithFiat.set(FeeUtil.getTradeFeeWithFiatEquivalent(offerUtil,
+ dataModel.getMakerFeeInBtc(),
+ true,
+ btcFormatter));
+ tradeFeeInBsqWithFiat.set(FeeUtil.getTradeFeeWithFiatEquivalent(offerUtil,
+ dataModel.getMakerFeeInBsq(),
+ false,
+ bsqFormatter));
}
+
private void updateMarketPriceAvailable() {
marketPrice = priceFeedService.getMarketPrice(dataModel.getTradeCurrencyCode().get());
marketPriceAvailableProperty.set(marketPrice == null || !marketPrice.isExternallyProvidedPrice() ? 0 : 1);
@@ -985,15 +960,23 @@ public String getSecurityDepositWithCode() {
return btcFormatter.formatCoinWithCode(dataModel.getSecurityDeposit());
}
+
public String getTradeFee() {
- //TODO use last bisq market price to estimate BSQ val
- final Coin makerFeeAsCoin = dataModel.getMakerFee();
- final String makerFee = getFormatterForMakerFee().formatCoinWithCode(makerFeeAsCoin);
- if (dataModel.isCurrencyForMakerFeeBtc())
- return makerFee + GUIUtil.getPercentageOfTradeAmount(makerFeeAsCoin, dataModel.getAmount().get(),
+ if (dataModel.isCurrencyForMakerFeeBtc()) {
+ return FeeUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil,
+ dataModel.getMakerFeeInBtc(),
+ dataModel.getAmount().get(),
+ true,
+ btcFormatter,
FeeService.getMinMakerFee(dataModel.isCurrencyForMakerFeeBtc()));
- else
- return makerFee + " (" + Res.get("shared.tradingFeeInBsqInfo", btcFormatter.formatCoinWithCode(makerFeeAsCoin)) + ")";
+ } else {
+ // For BSQ we use the fiat equivalent only. Calculating the % value would require to
+ // calculate the BTC value of the BSQ fee and use that...
+ return FeeUtil.getTradeFeeWithFiatEquivalent(offerUtil,
+ dataModel.getMakerFeeInBsq(),
+ false,
+ bsqFormatter);
+ }
}
public String getMakerFeePercentage() {
@@ -1025,10 +1008,13 @@ public String getFundsStructure() {
}
public String getTxFee() {
- Coin txFeeAsCoin = dataModel.getTxFee();
- return btcFormatter.formatCoinWithCode(txFeeAsCoin) +
- GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get(), Coin.ZERO);
-
+ return FeeUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil,
+ dataModel.getTxFee(),
+ dataModel.getAmount().get(),
+ true,
+ btcFormatter,
+ Coin.ZERO
+ );
}
public String getTxFeePercentage() {
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 0bf3855eb24..e7f7b3b6cc8 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
@@ -23,6 +23,7 @@
import bisq.desktop.main.MainView;
import bisq.desktop.main.funds.FundsView;
import bisq.desktop.main.funds.deposit.DepositView;
+import bisq.desktop.main.offer.FeeUtil;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
@@ -33,7 +34,6 @@
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.monetary.Price;
-import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferRestrictions;
@@ -76,8 +76,6 @@
import javafx.util.Callback;
-import java.util.Optional;
-
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -279,50 +277,23 @@ public void setIsCurrencyForTakerFeeBtc(boolean isCurrencyForTakerFeeBtc) {
}
private void applyTakerFee() {
- Coin takerFeeAsCoin = dataModel.getTakerFee();
- if (takerFeeAsCoin != null) {
- isTradeFeeVisible.setValue(true);
-
- tradeFee.set(getFormatterForTakerFee().formatCoin(takerFeeAsCoin));
-
- Coin makerFeeInBtc = dataModel.getTakerFeeInBtc();
- Optional optionalBtcFeeInFiat = offerUtil.getFeeInUserFiatCurrency(makerFeeInBtc,
- true,
- bsqFormatter);
- String btcFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBtc, optionalBtcFeeInFiat, btcFormatter);
- if (DevEnv.isDaoActivated()) {
- tradeFeeInBtcWithFiat.set(btcFeeWithFiatAmount);
- } else {
- tradeFeeInBtcWithFiat.set(btcFormatter.formatCoinWithCode(takerFeeAsCoin));
- }
-
- Coin makerFeeInBsq = dataModel.getTakerFeeInBsq();
- Optional optionalBsqFeeInFiat = offerUtil.getFeeInUserFiatCurrency(makerFeeInBsq,
- false,
- bsqFormatter);
- String bsqFeeWithFiatAmount = DisplayUtils.getFeeWithFiatAmount(makerFeeInBsq, optionalBsqFeeInFiat, bsqFormatter);
- if (DevEnv.isDaoActivated()) {
- tradeFeeInBsqWithFiat.set(bsqFeeWithFiatAmount);
- } else {
- // Before DAO is enabled we show fee as fiat and % in second line
- String feeInFiatAsString;
- if (optionalBtcFeeInFiat != null && optionalBtcFeeInFiat.isPresent()) {
- feeInFiatAsString = DisplayUtils.formatVolumeWithCode(optionalBtcFeeInFiat.get());
- } else {
- feeInFiatAsString = Res.get("shared.na");
- }
-
- double amountAsLong = (double) dataModel.getAmount().get().value;
- double makerFeeInBtcAsLong = (double) makerFeeInBtc.value;
- double percent = makerFeeInBtcAsLong / amountAsLong;
-
- tradeFeeInBsqWithFiat.set(Res.get("createOffer.tradeFee.fiatAndPercent",
- feeInFiatAsString,
- FormattingUtils.formatToPercentWithSymbol(percent)));
- }
- }
tradeFeeDescription.set(DevEnv.isDaoActivated() ? Res.get("createOffer.tradeFee.descriptionBSQEnabled") :
Res.get("createOffer.tradeFee.descriptionBTCOnly"));
+ Coin takerFeeAsCoin = dataModel.getTakerFee();
+ if (takerFeeAsCoin == null) {
+ return;
+ }
+
+ isTradeFeeVisible.setValue(true);
+ tradeFee.set(getFormatterForTakerFee().formatCoin(takerFeeAsCoin));
+ tradeFeeInBtcWithFiat.set(FeeUtil.getTradeFeeWithFiatEquivalent(offerUtil,
+ dataModel.getTakerFeeInBtc(),
+ true,
+ btcFormatter));
+ tradeFeeInBsqWithFiat.set(FeeUtil.getTradeFeeWithFiatEquivalent(offerUtil,
+ dataModel.getTakerFeeInBsq(),
+ false,
+ bsqFormatter));
}
@@ -706,14 +677,21 @@ public String getSecurityDepositWithCode() {
}
public String getTradeFee() {
- //TODO use last bisq market price to estimate BSQ val
- final Coin takerFeeAsCoin = dataModel.getTakerFee();
- final String takerFee = getFormatterForTakerFee().formatCoinWithCode(takerFeeAsCoin);
- if (dataModel.isCurrencyForTakerFeeBtc())
- return takerFee + GUIUtil.getPercentageOfTradeAmount(takerFeeAsCoin, dataModel.getAmount().get(),
- FeeService.getMinTakerFee(dataModel.isCurrencyForTakerFeeBtc()));
- else
- return takerFee + " (" + Res.get("shared.tradingFeeInBsqInfo", btcFormatter.formatCoinWithCode(takerFeeAsCoin)) + ")";
+ if (dataModel.isCurrencyForTakerFeeBtc()) {
+ return FeeUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil,
+ dataModel.getTakerFeeInBtc(),
+ dataModel.getAmount().get(),
+ true,
+ btcFormatter,
+ FeeService.getMinMakerFee(dataModel.isCurrencyForTakerFeeBtc()));
+ } else {
+ // For BSQ we use the fiat equivalent only. Calculating the % value would require to
+ // calculate the BTC value of the BSQ fee and use that...
+ return FeeUtil.getTradeFeeWithFiatEquivalent(offerUtil,
+ dataModel.getTakerFeeInBsq(),
+ false,
+ bsqFormatter);
+ }
}
public String getTakerFeePercentage() {
@@ -733,11 +711,13 @@ public String getTotalToPayInfo() {
}
public String getTxFee() {
- Coin txFeeAsCoin = dataModel.getTotalTxFee();
- return btcFormatter.formatCoinWithCode(txFeeAsCoin) +
- GUIUtil.getPercentageOfTradeAmount(txFeeAsCoin, dataModel.getAmount().get(),
- Coin.ZERO);
-
+ return FeeUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil,
+ dataModel.getTotalTxFee(),
+ dataModel.getAmount().get(),
+ true,
+ btcFormatter,
+ Coin.ZERO
+ );
}
public String getTxFeePercentage() {
diff --git a/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java b/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java
index 83a0d157de3..f8d144e6fa9 100644
--- a/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java
+++ b/desktop/src/main/java/bisq/desktop/util/DisplayUtils.java
@@ -126,7 +126,7 @@ public static String formatVolumeWithCode(Volume volume) {
return formatVolume(volume, FIAT_VOLUME_FORMAT, true);
}
- static String formatAverageVolumeWithCode(Volume volume) {
+ public static String formatAverageVolumeWithCode(Volume volume) {
return formatVolume(volume, FIAT_VOLUME_FORMAT.minDecimals(2), true);
}
@@ -257,16 +257,16 @@ public static String formatPrice(Price price, Boolean decimalAligned, int maxPla
public static String getFeeWithFiatAmount(Coin makerFeeAsCoin,
Optional optionalFeeInFiat,
CoinFormatter formatter) {
- String fee = makerFeeAsCoin != null ? formatter.formatCoinWithCode(makerFeeAsCoin) : Res.get("shared.na");
- String feeInFiatAsString;
+ String feeInBtc = makerFeeAsCoin != null ? formatter.formatCoinWithCode(makerFeeAsCoin) : Res.get("shared.na");
if (optionalFeeInFiat != null && optionalFeeInFiat.isPresent()) {
- feeInFiatAsString = formatAverageVolumeWithCode(optionalFeeInFiat.get());
+ String feeInFiat = formatAverageVolumeWithCode(optionalFeeInFiat.get());
+ return Res.get("feeOptionWindow.fee", feeInBtc, feeInFiat);
} else {
- feeInFiatAsString = Res.get("shared.na");
+ return feeInBtc;
}
- return Res.get("feeOptionWindow.fee", fee, feeInFiatAsString);
}
+
/**
* Converts to a coin with max. 4 decimal places. Last place gets rounded.
* 0.01234 -> 0.0123