This commit is contained in:
Manfred Karrer 2019-04-19 20:26:31 -05:00
commit ad4be15eea
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
15 changed files with 104 additions and 59 deletions

View file

@ -1354,6 +1354,7 @@ message PreferencesPayload {
string take_offer_selected_payment_account_id = 49; string take_offer_selected_payment_account_id = 49;
double buyer_security_deposit_as_percent = 50; double buyer_security_deposit_as_percent = 50;
int32 ignore_dust_threshold = 51; int32 ignore_dust_threshold = 51;
double buyer_security_deposit_as_percent_for_crypto = 52;
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -18,9 +18,13 @@
package bisq.core.btc.wallet; package bisq.core.btc.wallet;
import bisq.core.app.BisqEnvironment; import bisq.core.app.BisqEnvironment;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import javax.annotation.Nullable;
public class Restrictions { public class Restrictions {
private static Coin MIN_TRADE_AMOUNT; private static Coin MIN_TRADE_AMOUNT;
private static Coin MIN_BUYER_SECURITY_DEPOSIT; private static Coin MIN_BUYER_SECURITY_DEPOSIT;
@ -50,16 +54,25 @@ public class Restrictions {
return MIN_TRADE_AMOUNT; return MIN_TRADE_AMOUNT;
} }
public static double getDefaultBuyerSecurityDepositAsPercent() { public static double getDefaultBuyerSecurityDepositAsPercent(@Nullable PaymentAccount paymentAccount) {
if (PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount))
return 0.02; // 2% of trade amount.
else
return 0.1; // 10% of trade amount. return 0.1; // 10% of trade amount.
} }
public static double getMinBuyerSecurityDepositAsPercent() { public static double getMinBuyerSecurityDepositAsPercent(@Nullable PaymentAccount paymentAccount) {
if (PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount))
return 0.005; // 0.5% of trade amount.
else
return 0.05; // 5% of trade amount. return 0.05; // 5% of trade amount.
} }
public static double getMaxBuyerSecurityDepositAsPercent() { public static double getMaxBuyerSecurityDepositAsPercent(@Nullable PaymentAccount paymentAccount) {
return 0.5; // 50% of trade amount. For a 1 BTC trade it is about 800 USD @ 4000 USD/BTC if (PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount))
return 0.2; // 20% of trade amount. For a 1 BTC trade it is about 800 USD @ 4000 USD/BTC
else
return 0.5; // 50% of trade amount. For a 1 BTC trade it is about 2000 USD @ 4000 USD/BTC
} }
// We use MIN_BUYER_SECURITY_DEPOSIT as well as lower bound in case of small trade amounts. // We use MIN_BUYER_SECURITY_DEPOSIT as well as lower bound in case of small trade amounts.

View file

@ -353,12 +353,12 @@ public class OfferUtil {
Coin makerFeeAsCoin) { Coin makerFeeAsCoin) {
checkNotNull(makerFeeAsCoin, "makerFee must not be null"); checkNotNull(makerFeeAsCoin, "makerFee must not be null");
checkNotNull(p2PService.getAddress(), "Address must not be null"); checkNotNull(p2PService.getAddress(), "Address must not be null");
checkArgument(buyerSecurityDeposit <= Restrictions.getMaxBuyerSecurityDepositAsPercent(), checkArgument(buyerSecurityDeposit <= Restrictions.getMaxBuyerSecurityDepositAsPercent(paymentAccount),
"securityDeposit must not exceed " + "securityDeposit must not exceed " +
Restrictions.getMaxBuyerSecurityDepositAsPercent()); Restrictions.getMaxBuyerSecurityDepositAsPercent(paymentAccount));
checkArgument(buyerSecurityDeposit >= Restrictions.getMinBuyerSecurityDepositAsPercent(), checkArgument(buyerSecurityDeposit >= Restrictions.getMinBuyerSecurityDepositAsPercent(paymentAccount),
"securityDeposit must not be less than " + "securityDeposit must not be less than " +
Restrictions.getMinBuyerSecurityDepositAsPercent()); Restrictions.getMinBuyerSecurityDepositAsPercent(paymentAccount));
checkArgument(!filterManager.isCurrencyBanned(currencyCode), checkArgument(!filterManager.isCurrencyBanned(currencyCode),
Res.get("offerbook.warning.currencyBanned")); Res.get("offerbook.warning.currencyBanned"));
checkArgument(!filterManager.isPaymentMethodBanned(paymentAccount.getPaymentMethod()), checkArgument(!filterManager.isPaymentMethodBanned(paymentAccount.getPaymentMethod()),

View file

@ -19,6 +19,7 @@ package bisq.core.payment;
import bisq.core.locale.Country; import bisq.core.locale.Country;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.payment.payload.PaymentMethod;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -114,6 +115,11 @@ public class PaymentAccountUtil {
return null; return null;
} }
public static boolean isCryptoCurrencyAccount(PaymentAccount paymentAccount) {
return (paymentAccount != null && paymentAccount.getPaymentMethod().equals(PaymentMethod.BLOCK_CHAINS) ||
paymentAccount != null && paymentAccount.getPaymentMethod().equals(PaymentMethod.BLOCK_CHAINS_INSTANT));
}
// TODO no code duplication found in UI code (added for API) // TODO no code duplication found in UI code (added for API)
// That is optional and set to null if not supported (AltCoins,...) // That is optional and set to null if not supported (AltCoins,...)
/* public static String getCountryCode(PaymentAccount paymentAccount) { /* public static String getCountryCode(PaymentAccount paymentAccount) {

View file

@ -32,6 +32,7 @@ import bisq.core.locale.FiatCurrency;
import bisq.core.locale.GlobalSettings; import bisq.core.locale.GlobalSettings;
import bisq.core.locale.TradeCurrency; import bisq.core.locale.TradeCurrency;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
import bisq.network.p2p.network.BridgeAddressProvider; import bisq.network.p2p.network.BridgeAddressProvider;
@ -493,9 +494,13 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
withdrawalTxFeeInBytesProperty.set(withdrawalTxFeeInBytes); withdrawalTxFeeInBytesProperty.set(withdrawalTxFeeInBytes);
} }
public void setBuyerSecurityDepositAsPercent(double buyerSecurityDepositAsPercent) { public void setBuyerSecurityDepositAsPercent(double buyerSecurityDepositAsPercent, PaymentAccount paymentAccount) {
double max = Restrictions.getMaxBuyerSecurityDepositAsPercent(); double max = Restrictions.getMaxBuyerSecurityDepositAsPercent(paymentAccount);
double min = Restrictions.getMinBuyerSecurityDepositAsPercent(); double min = Restrictions.getMinBuyerSecurityDepositAsPercent(paymentAccount);
if (PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount))
prefPayload.setBuyerSecurityDepositAsPercentForCrypto(Math.min(max, Math.max(min, buyerSecurityDepositAsPercent)));
else
prefPayload.setBuyerSecurityDepositAsPercent(Math.min(max, Math.max(min, buyerSecurityDepositAsPercent))); prefPayload.setBuyerSecurityDepositAsPercent(Math.min(max, Math.max(min, buyerSecurityDepositAsPercent)));
persist(); persist();
} }
@ -715,15 +720,16 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
return withdrawalTxFeeInBytesProperty; return withdrawalTxFeeInBytesProperty;
} }
public double getBuyerSecurityDepositAsPercent() { public double getBuyerSecurityDepositAsPercent(PaymentAccount paymentAccount) {
double value = prefPayload.getBuyerSecurityDepositAsPercent(); double value = PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount) ?
prefPayload.getBuyerSecurityDepositAsPercentForCrypto() : prefPayload.getBuyerSecurityDepositAsPercent();
if (value < Restrictions.getMinBuyerSecurityDepositAsPercent()) { if (value < Restrictions.getMinBuyerSecurityDepositAsPercent(paymentAccount)) {
value = Restrictions.getMinBuyerSecurityDepositAsPercent(); value = Restrictions.getMinBuyerSecurityDepositAsPercent(paymentAccount);
setBuyerSecurityDepositAsPercent(value); setBuyerSecurityDepositAsPercent(value, paymentAccount);
} }
return value == 0 ? Restrictions.getDefaultBuyerSecurityDepositAsPercent() : value; return value == 0 ? Restrictions.getDefaultBuyerSecurityDepositAsPercent(paymentAccount) : value;
} }
//TODO remove and use isPayFeeInBtc instead //TODO remove and use isPayFeeInBtc instead

View file

@ -17,11 +17,11 @@
package bisq.core.user; package bisq.core.user;
import bisq.core.btc.wallet.Restrictions;
import bisq.core.locale.Country; import bisq.core.locale.Country;
import bisq.core.locale.CryptoCurrency; import bisq.core.locale.CryptoCurrency;
import bisq.core.locale.FiatCurrency; import bisq.core.locale.FiatCurrency;
import bisq.core.locale.TradeCurrency; import bisq.core.locale.TradeCurrency;
import bisq.core.payment.CryptoCurrencyAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.proto.CoreProtoResolver; import bisq.core.proto.CoreProtoResolver;
@ -47,6 +47,8 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent;
@Slf4j @Slf4j
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@ -120,8 +122,9 @@ public final class PreferencesPayload implements PersistableEnvelope {
String rpcPw; String rpcPw;
@Nullable @Nullable
String takeOfferSelectedPaymentAccountId; String takeOfferSelectedPaymentAccountId;
private double buyerSecurityDepositAsPercent = Restrictions.getDefaultBuyerSecurityDepositAsPercent(); private double buyerSecurityDepositAsPercent = getDefaultBuyerSecurityDepositAsPercent(null);
private int ignoreDustThreshold = 600; private int ignoreDustThreshold = 600;
private double buyerSecurityDepositAsPercentForCrypto = getDefaultBuyerSecurityDepositAsPercent(new CryptoCurrencyAccount());
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -178,8 +181,9 @@ public final class PreferencesPayload implements PersistableEnvelope {
.setUsePriceNotifications(usePriceNotifications) .setUsePriceNotifications(usePriceNotifications)
.setUseStandbyMode(useStandbyMode) .setUseStandbyMode(useStandbyMode)
.setIsDaoFullNode(isDaoFullNode) .setIsDaoFullNode(isDaoFullNode)
.setBuyerSecurityDepositAsPercent(buyerSecurityDepositAsPercent). .setBuyerSecurityDepositAsPercent(buyerSecurityDepositAsPercent)
setIgnoreDustThreshold(ignoreDustThreshold); .setIgnoreDustThreshold(ignoreDustThreshold)
.setBuyerSecurityDepositAsPercentForCrypto(buyerSecurityDepositAsPercentForCrypto);
Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory); Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory);
Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((PB.TradeCurrency) e.toProtoMessage())); Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((PB.TradeCurrency) e.toProtoMessage()));
Optional.ofNullable(offerBookChartScreenCurrencyCode).ifPresent(builder::setOfferBookChartScreenCurrencyCode); Optional.ofNullable(offerBookChartScreenCurrencyCode).ifPresent(builder::setOfferBookChartScreenCurrencyCode);
@ -262,6 +266,8 @@ public final class PreferencesPayload implements PersistableEnvelope {
proto.getRpcPw().isEmpty() ? null : proto.getRpcPw(), proto.getRpcPw().isEmpty() ? null : proto.getRpcPw(),
proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId(), proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId(),
proto.getBuyerSecurityDepositAsPercent(), proto.getBuyerSecurityDepositAsPercent(),
proto.getIgnoreDustThreshold()); proto.getIgnoreDustThreshold(),
proto.getBuyerSecurityDepositAsPercentForCrypto());
} }
} }

View file

@ -493,6 +493,7 @@ editOffer.confirmEdit=Confirm: Edit offer
editOffer.publishOffer=Publishing your offer. editOffer.publishOffer=Publishing your offer.
editOffer.failed=Editing of offer failed:\n{0} editOffer.failed=Editing of offer failed:\n{0}
editOffer.success=Your offer has been successfully edited. editOffer.success=Your offer has been successfully edited.
editOffer.invalidDeposit=The buyer's security deposit is not within the constraints defined by the Bisq DAO and can no longer be edited.
#################################################################### ####################################################################
# Portfolio # Portfolio

View file

@ -333,6 +333,7 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupCompleteList
.show()); .show());
bisqSetup.setDisplayAlertHandler(alert -> new DisplayAlertMessageWindow() bisqSetup.setDisplayAlertHandler(alert -> new DisplayAlertMessageWindow()
.alertMessage(alert) .alertMessage(alert)
.closeButtonText(Res.get("shared.close"))
.onClose(() -> { .onClose(() -> {
user.setDisplayedAlert(alert); user.setDisplayedAlert(alert);
}) })

View file

@ -180,7 +180,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
addressEntry = btcWalletService.getOrCreateAddressEntry(offerId, AddressEntry.Context.OFFER_FUNDING); addressEntry = btcWalletService.getOrCreateAddressEntry(offerId, AddressEntry.Context.OFFER_FUNDING);
useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice()); useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice());
buyerSecurityDeposit.set(preferences.getBuyerSecurityDepositAsPercent()); buyerSecurityDeposit.set(preferences.getBuyerSecurityDepositAsPercent(null));
sellerSecurityDeposit.set(Restrictions.getSellerSecurityDepositAsPercent()); sellerSecurityDeposit.set(Restrictions.getSellerSecurityDepositAsPercent());
btcBalanceListener = new BalanceListener(getAddressEntry().getAddress()) { btcBalanceListener = new BalanceListener(getAddressEntry().getAddress()) {
@ -436,6 +436,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
setTradeCurrencyFromPaymentAccount(paymentAccount); setTradeCurrencyFromPaymentAccount(paymentAccount);
buyerSecurityDeposit.set(preferences.getBuyerSecurityDepositAsPercent(getPaymentAccount()));
long myLimit = accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get()); long myLimit = accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get());
if (amount.get() != null) if (amount.get() != null)
this.amount.set(Coin.valueOf(Math.min(amount.get().value, myLimit))); this.amount.set(Coin.valueOf(Math.min(amount.get().value, myLimit)));
@ -710,7 +712,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
void setBuyerSecurityDeposit(double value) { void setBuyerSecurityDeposit(double value) {
this.buyerSecurityDeposit.set(value); this.buyerSecurityDeposit.set(value);
preferences.setBuyerSecurityDepositAsPercent(value); preferences.setBuyerSecurityDepositAsPercent(value, getPaymentAccount());
} }
protected boolean isUseMarketBasedPriceValue() { protected boolean isUseMarketBasedPriceValue() {

View file

@ -84,7 +84,7 @@ import static javafx.beans.binding.Bindings.createStringBinding;
public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> extends ActivatableWithDataModel<M> { public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> extends ActivatableWithDataModel<M> {
private final BtcValidator btcValidator; private final BtcValidator btcValidator;
private final BsqValidator bsqValidator; private final BsqValidator bsqValidator;
private final SecurityDepositValidator securityDepositValidator; protected final SecurityDepositValidator securityDepositValidator;
private final P2PService p2PService; private final P2PService p2PService;
private final WalletsSetup walletsSetup; private final WalletsSetup walletsSetup;
private final PriceFeedService priceFeedService; private final PriceFeedService priceFeedService;
@ -104,7 +104,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
public final StringProperty amount = new SimpleStringProperty(); public final StringProperty amount = new SimpleStringProperty();
public final StringProperty minAmount = new SimpleStringProperty(); public final StringProperty minAmount = new SimpleStringProperty();
final StringProperty buyerSecurityDeposit = new SimpleStringProperty(); protected final StringProperty buyerSecurityDeposit = new SimpleStringProperty();
final StringProperty buyerSecurityDepositInBTC = new SimpleStringProperty(); final StringProperty buyerSecurityDepositInBTC = new SimpleStringProperty();
final StringProperty buyerSecurityDepositLabel = new SimpleStringProperty(); final StringProperty buyerSecurityDepositLabel = new SimpleStringProperty();
@ -599,6 +599,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
amountDescription = Res.get("createOffer.amountPriceBox.amountDescription", amountDescription = Res.get("createOffer.amountPriceBox.amountDescription",
isBuy ? Res.get("shared.buy") : Res.get("shared.sell")); isBuy ? Res.get("shared.buy") : Res.get("shared.sell"));
securityDepositValidator.setPaymentAccount(dataModel.paymentAccount);
buyerSecurityDeposit.set(btcFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get())); buyerSecurityDeposit.set(btcFormatter.formatToPercent(dataModel.getBuyerSecurityDeposit().get()));
buyerSecurityDepositLabel.set(getSecurityDepositLabel()); buyerSecurityDepositLabel.set(getSecurityDepositLabel());
@ -663,6 +664,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(dataModel.getTradeCurrencyCode().get())); btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(dataModel.getTradeCurrencyCode().get()));
btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit())); btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit()));
securityDepositValidator.setPaymentAccount(paymentAccount);
} }
public void onCurrencySelected(TradeCurrency tradeCurrency) { public void onCurrencySelected(TradeCurrency tradeCurrency) {
@ -853,7 +856,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
InputValidator.ValidationResult result = securityDepositValidator.validate(buyerSecurityDeposit.get()); InputValidator.ValidationResult result = securityDepositValidator.validate(buyerSecurityDeposit.get());
buyerSecurityDepositValidationResult.set(result); buyerSecurityDepositValidationResult.set(result);
if (result.isValid) { if (result.isValid) {
double defaultSecurityDeposit = Restrictions.getDefaultBuyerSecurityDepositAsPercent(); double defaultSecurityDeposit = Restrictions.getDefaultBuyerSecurityDepositAsPercent(getPaymentAccount());
String key = "buyerSecurityDepositIsLowerAsDefault"; String key = "buyerSecurityDepositIsLowerAsDefault";
double depositAsDouble = btcFormatter.parsePercentStringToDouble(buyerSecurityDeposit.get()); double depositAsDouble = btcFormatter.parsePercentStringToDouble(buyerSecurityDeposit.get());
if (preferences.showAgain(key) && depositAsDouble < defaultSecurityDeposit) { if (preferences.showAgain(key) && depositAsDouble < defaultSecurityDeposit) {
@ -1121,7 +1124,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (buyerSecurityDeposit.get() != null && !buyerSecurityDeposit.get().isEmpty()) { if (buyerSecurityDeposit.get() != null && !buyerSecurityDeposit.get().isEmpty()) {
dataModel.setBuyerSecurityDeposit(btcFormatter.parsePercentStringToDouble(buyerSecurityDeposit.get())); dataModel.setBuyerSecurityDeposit(btcFormatter.parsePercentStringToDouble(buyerSecurityDeposit.get()));
} else { } else {
dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()); dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent(getPaymentAccount()));
} }
} }

View file

@ -17,7 +17,6 @@
package bisq.desktop.main.overlays.windows; package bisq.desktop.main.overlays.windows;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.HyperlinkWithIcon; import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.main.overlays.Overlay; import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.FormBuilder; import bisq.desktop.util.FormBuilder;
@ -25,13 +24,10 @@ import bisq.desktop.util.FormBuilder;
import bisq.core.alert.Alert; import bisq.core.alert.Alert;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import javafx.scene.layout.GridPane;
import javafx.geometry.Insets;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static bisq.desktop.util.FormBuilder.addMultilineLabel;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow> { public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow> {
@ -50,10 +46,22 @@ public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow
public void show() { public void show() {
width = 768; width = 768;
// need to set headLine, otherwise the fields will not be created in addHeadLine // need to set headLine, otherwise the fields will not be created in addHeadLine
headLine = Res.get("displayAlertMessageWindow.headline");
createGridPane(); createGridPane();
checkNotNull(alert, "alertMessage must not be null");
if (alert.isUpdateInfo()) {
information("");
headLine = Res.get("displayAlertMessageWindow.update.headline");
} else {
error("");
headLine = Res.get("displayAlertMessageWindow.headline");
}
headLine = Res.get("displayAlertMessageWindow.headline");
addHeadLine(); addHeadLine();
addContent(); addContent();
addButtons();
applyStyles(); applyStyles();
display(); display();
} }
@ -69,28 +77,13 @@ public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow
private void addContent() { private void addContent() {
checkNotNull(alert, "alertMessage must not be null"); checkNotNull(alert, "alertMessage must not be null");
FormBuilder.addMultilineLabel(gridPane, ++rowIndex, alert.getMessage(), 10); addMultilineLabel(gridPane, ++rowIndex, alert.getMessage(), 10);
if (alert.isUpdateInfo()) { if (alert.isUpdateInfo()) {
headLine = Res.get("displayAlertMessageWindow.update.headline");
headLineLabel.getStyleClass().addAll("headline-label", "highlight");
String url = "https://bisq.network/downloads"; String url = "https://bisq.network/downloads";
HyperlinkWithIcon hyperlinkWithIcon = FormBuilder.addLabelHyperlinkWithIcon(gridPane, ++rowIndex, HyperlinkWithIcon hyperlinkWithIcon = FormBuilder.addLabelHyperlinkWithIcon(gridPane, ++rowIndex,
Res.get("displayAlertMessageWindow.update.download"), url, url).second; Res.get("displayAlertMessageWindow.update.download"), url, url).second;
hyperlinkWithIcon.setMaxWidth(550); hyperlinkWithIcon.setMaxWidth(550);
} else {
headLine = Res.get("displayAlertMessageWindow.headline");
headLineLabel.getStyleClass().addAll("headline-label", "error-text");
} }
closeButton = new AutoTooltipButton(Res.get("shared.close"));
closeButton.setOnAction(e -> {
hide();
closeHandlerOptional.ifPresent(Runnable::run);
});
GridPane.setRowIndex(closeButton, ++rowIndex);
GridPane.setColumnIndex(closeButton, 1);
gridPane.getChildren().add(closeButton);
GridPane.setMargin(closeButton, new Insets(10, 0, 0, 0));
} }

View file

@ -148,11 +148,15 @@ public class EditOfferView extends MutableOfferView<EditOfferViewModel> {
model.onStartEditOffer(errorMessage -> { model.onStartEditOffer(errorMessage -> {
log.error(errorMessage); log.error(errorMessage);
new Popup<>().warning(Res.get("editOffer.failed", errorMessage)) new Popup<>().warning(Res.get("editOffer.failed", errorMessage))
.onClose(() -> { .onClose(this::close)
close();
})
.show(); .show();
}); });
if (!model.isSecurityDepositValid()) {
new Popup<>().warning(Res.get("editOffer.invalidDeposit"))
.onClose(this::close)
.show();
}
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -80,4 +80,8 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> {
price.set(btcFormatter.formatPrice(null)); price.set(btcFormatter.formatPrice(null));
price.set(btcFormatter.formatPrice(dataModel.getPrice().get())); price.set(btcFormatter.formatPrice(dataModel.getPrice().get()));
} }
public boolean isSecurityDepositValid() {
return securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid;
}
} }

View file

@ -19,6 +19,7 @@ package bisq.desktop.util.validation;
import bisq.core.btc.wallet.Restrictions; import bisq.core.btc.wallet.Restrictions;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.payment.PaymentAccount;
import bisq.core.util.BSFormatter; import bisq.core.util.BSFormatter;
import javax.inject.Inject; import javax.inject.Inject;
@ -26,12 +27,16 @@ import javax.inject.Inject;
public class SecurityDepositValidator extends NumberValidator { public class SecurityDepositValidator extends NumberValidator {
private final BSFormatter formatter; private final BSFormatter formatter;
private PaymentAccount paymentAccount;
@Inject @Inject
public SecurityDepositValidator(BSFormatter formatter) { public SecurityDepositValidator(BSFormatter formatter) {
this.formatter = formatter; this.formatter = formatter;
} }
public void setPaymentAccount(PaymentAccount paymentAccount) {
this.paymentAccount = paymentAccount;
}
@Override @Override
public ValidationResult validate(String input) { public ValidationResult validate(String input) {
@ -54,7 +59,7 @@ public class SecurityDepositValidator extends NumberValidator {
private ValidationResult validateIfNotTooLowPercentageValue(String input) { private ValidationResult validateIfNotTooLowPercentageValue(String input) {
try { try {
double percentage = formatter.parsePercentStringToDouble(input); double percentage = formatter.parsePercentStringToDouble(input);
double minPercentage = Restrictions.getMinBuyerSecurityDepositAsPercent(); double minPercentage = Restrictions.getMinBuyerSecurityDepositAsPercent(paymentAccount);
if (percentage < minPercentage) if (percentage < minPercentage)
return new ValidationResult(false, return new ValidationResult(false,
Res.get("validation.inputTooSmall", formatter.formatToPercentWithSymbol(minPercentage))); Res.get("validation.inputTooSmall", formatter.formatToPercentWithSymbol(minPercentage)));
@ -68,7 +73,7 @@ public class SecurityDepositValidator extends NumberValidator {
private ValidationResult validateIfNotTooHighPercentageValue(String input) { private ValidationResult validateIfNotTooHighPercentageValue(String input) {
try { try {
double percentage = formatter.parsePercentStringToDouble(input); double percentage = formatter.parsePercentStringToDouble(input);
double maxPercentage = Restrictions.getMaxBuyerSecurityDepositAsPercent(); double maxPercentage = Restrictions.getMaxBuyerSecurityDepositAsPercent(paymentAccount);
if (percentage > maxPercentage) if (percentage > maxPercentage)
return new ValidationResult(false, return new ValidationResult(false,
Res.get("validation.inputTooLarge", formatter.formatToPercentWithSymbol(maxPercentage))); Res.get("validation.inputTooLarge", formatter.formatToPercentWithSymbol(maxPercentage)));

View file

@ -66,7 +66,7 @@ public class CreateOfferDataModelTest {
when(btcWalletService.getOrCreateAddressEntry(anyString(), any())).thenReturn(addressEntry); when(btcWalletService.getOrCreateAddressEntry(anyString(), any())).thenReturn(addressEntry);
when(preferences.isUsePercentageBasedPrice()).thenReturn(true); when(preferences.isUsePercentageBasedPrice()).thenReturn(true);
when(preferences.getBuyerSecurityDepositAsPercent()).thenReturn(0.01); when(preferences.getBuyerSecurityDepositAsPercent(null)).thenReturn(0.01);
model = new CreateOfferDataModel(null, btcWalletService, model = new CreateOfferDataModel(null, btcWalletService,
null, preferences, user, null, null, preferences, user, null,