Skip to content

Commit

Permalink
Improve trade fee display at create and take offer screens and popups
Browse files Browse the repository at this point in the history
  • Loading branch information
chimp1984 committed Dec 20, 2020
1 parent b04a56e commit bf72073
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 123 deletions.
14 changes: 11 additions & 3 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -454,15 +454,21 @@ 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
createOffer.alreadyFunded=You had already funded that offer.\nYour funds have been moved to your local Bisq wallet and are available for withdrawal in the \"Funds/Send funds\" screen.
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\
Expand Down Expand Up @@ -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})


####################################################################
Expand Down
82 changes: 82 additions & 0 deletions desktop/src/main/java/bisq/desktop/main/offer/FeeUtil.java
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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<Volume> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<M extends MutableOfferDataModel> extends ActivatableWithDataModel<M> {
private final BtcValidator btcValidator;
private final BsqValidator bsqValidator;
Expand Down Expand Up @@ -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<Volume> 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<Volume> 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);
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down
Loading

0 comments on commit bf72073

Please sign in to comment.