From fd2c0f335f064d99f94c33a47f04c818e6a6b1fc Mon Sep 17 00:00:00 2001 From: woodser Date: Mon, 21 Jul 2025 09:57:54 -0400 Subject: [PATCH] set minimum trade amount to 0.05 XMR (#1857) --- .../haveno/apitest/method/MethodTest.java | 4 +-- .../haveno/core/offer/OfferBookService.java | 2 +- .../java/haveno/core/offer/OfferUtil.java | 12 ++++----- .../haveno/core/offer/OpenOfferManager.java | 20 +++++++------- .../validation/SecurityDepositValidator.java | 4 +-- .../java/haveno/core/user/Preferences.java | 10 +++---- .../haveno/core/user/PreferencesPayload.java | 6 ++--- .../haveno/core/xmr/wallet/Restrictions.java | 26 ++++++++++++------- .../haveno/core/util/coin/CoinUtilTest.java | 14 +++++----- .../main/offer/MutableOfferDataModel.java | 20 +++++++------- .../main/offer/MutableOfferViewModel.java | 20 +++++++------- .../editoffer/EditOfferDataModel.java | 4 +-- 12 files changed, 75 insertions(+), 67 deletions(-) diff --git a/apitest/src/test/java/haveno/apitest/method/MethodTest.java b/apitest/src/test/java/haveno/apitest/method/MethodTest.java index 01c7a3bfd3..0007cc6c3a 100644 --- a/apitest/src/test/java/haveno/apitest/method/MethodTest.java +++ b/apitest/src/test/java/haveno/apitest/method/MethodTest.java @@ -43,7 +43,7 @@ import java.util.stream.Collectors; import static haveno.apitest.config.ApiTestConfig.BTC; import static haveno.apitest.config.ApiTestRateMeterInterceptorConfig.getTestRateMeterInterceptorConfig; import static haveno.cli.table.builder.TableType.BTC_BALANCE_TBL; -import static haveno.core.xmr.wallet.Restrictions.getDefaultSecurityDepositAsPercent; +import static haveno.core.xmr.wallet.Restrictions.getDefaultSecurityDepositPct; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.stream; @@ -158,7 +158,7 @@ public class MethodTest extends ApiTestCase { } public static final Supplier defaultSecurityDepositPct = () -> { - var defaultPct = BigDecimal.valueOf(getDefaultSecurityDepositAsPercent()); + var defaultPct = BigDecimal.valueOf(getDefaultSecurityDepositPct()); if (defaultPct.precision() != 2) throw new IllegalStateException(format( "Unexpected decimal precision, expected 2 but actual is %d%n." diff --git a/core/src/main/java/haveno/core/offer/OfferBookService.java b/core/src/main/java/haveno/core/offer/OfferBookService.java index 3057807b84..0fde4e5031 100644 --- a/core/src/main/java/haveno/core/offer/OfferBookService.java +++ b/core/src/main/java/haveno/core/offer/OfferBookService.java @@ -404,7 +404,7 @@ public class OfferBookService { } // validate max offers with same key images - if (numOffersWithSharedKeyImages > Restrictions.MAX_OFFERS_WITH_SHARED_FUNDS) throw new RuntimeException("More than " + Restrictions.MAX_OFFERS_WITH_SHARED_FUNDS + " offers exist with same same key images as new offerId=" + offerPayload.getId()); + if (numOffersWithSharedKeyImages > Restrictions.getMaxOffersWithSharedFunds()) throw new RuntimeException("More than " + Restrictions.getMaxOffersWithSharedFunds() + " offers exist with same same key images as new offerId=" + offerPayload.getId()); } } diff --git a/core/src/main/java/haveno/core/offer/OfferUtil.java b/core/src/main/java/haveno/core/offer/OfferUtil.java index 099eb15287..8792672321 100644 --- a/core/src/main/java/haveno/core/offer/OfferUtil.java +++ b/core/src/main/java/haveno/core/offer/OfferUtil.java @@ -61,8 +61,8 @@ import haveno.core.trade.statistics.ReferralIdService; import haveno.core.user.AutoConfirmSettings; import haveno.core.user.Preferences; import haveno.core.util.coin.CoinFormatter; -import static haveno.core.xmr.wallet.Restrictions.getMaxSecurityDepositAsPercent; -import static haveno.core.xmr.wallet.Restrictions.getMinSecurityDepositAsPercent; +import static haveno.core.xmr.wallet.Restrictions.getMaxSecurityDepositPct; +import static haveno.core.xmr.wallet.Restrictions.getMinSecurityDepositPct; import haveno.network.p2p.P2PService; import java.math.BigInteger; import java.util.HashMap; @@ -240,12 +240,12 @@ public class OfferUtil { PaymentAccount paymentAccount, String currencyCode) { checkNotNull(p2PService.getAddress(), "Address must not be null"); - checkArgument(securityDeposit <= getMaxSecurityDepositAsPercent(), + checkArgument(securityDeposit <= getMaxSecurityDepositPct(), "securityDeposit must not exceed " + - getMaxSecurityDepositAsPercent()); - checkArgument(securityDeposit >= getMinSecurityDepositAsPercent(), + getMaxSecurityDepositPct()); + checkArgument(securityDeposit >= getMinSecurityDepositPct(), "securityDeposit must not be less than " + - getMinSecurityDepositAsPercent() + " but was " + securityDeposit); + getMinSecurityDepositPct() + " but was " + securityDeposit); checkArgument(!filterManager.isCurrencyBanned(currencyCode), Res.get("offerbook.warning.currencyBanned")); checkArgument(!filterManager.isPaymentMethodBanned(paymentAccount.getPaymentMethod()), diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 7a070fc293..31ad71d5fa 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -540,8 +540,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // check clone limit int numClones = getOpenOfferGroup(sourceOffer.getGroupId()).size(); - if (numClones >= Restrictions.MAX_OFFERS_WITH_SHARED_FUNDS) { - errorMessageHandler.handleErrorMessage("Cannot create offer because maximum number of " + Restrictions.MAX_OFFERS_WITH_SHARED_FUNDS + " cloned offers with shared funds reached."); + if (numClones >= Restrictions.getMaxOffersWithSharedFunds()) { + errorMessageHandler.handleErrorMessage("Cannot create offer because maximum number of " + Restrictions.getMaxOffersWithSharedFunds() + " cloned offers with shared funds reached."); return; } } @@ -1565,8 +1565,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } // verify max length of extra info - if (offer.getOfferPayload().getExtraInfo() != null && offer.getOfferPayload().getExtraInfo().length() > Restrictions.MAX_EXTRA_INFO_LENGTH) { - errorMessage = "Extra info is too long for offer " + request.offerId + ". Max length is " + Restrictions.MAX_EXTRA_INFO_LENGTH + " but got " + offer.getOfferPayload().getExtraInfo().length(); + if (offer.getOfferPayload().getExtraInfo() != null && offer.getOfferPayload().getExtraInfo().length() > Restrictions.getMaxExtraInfoLength()) { + errorMessage = "Extra info is too long for offer " + request.offerId + ". Max length is " + Restrictions.getMaxExtraInfoLength() + " but got " + offer.getOfferPayload().getExtraInfo().length(); log.warn(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; @@ -1611,8 +1611,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } // verify maker security deposit - if (offer.getSellerSecurityDepositPct() != Restrictions.MIN_SECURITY_DEPOSIT_PCT) { - errorMessage = "Wrong seller security deposit for offer " + request.offerId + ". Expected " + Restrictions.MIN_SECURITY_DEPOSIT_PCT + " but got " + offer.getSellerSecurityDepositPct(); + if (offer.getSellerSecurityDepositPct() != Restrictions.getMinSecurityDepositPct()) { + errorMessage = "Wrong seller security deposit for offer " + request.offerId + ". Expected " + Restrictions.getMinSecurityDepositPct() + " but got " + offer.getSellerSecurityDepositPct(); log.warn(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; @@ -1652,16 +1652,16 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } // verify seller's security deposit - if (offer.getSellerSecurityDepositPct() < Restrictions.MIN_SECURITY_DEPOSIT_PCT) { - errorMessage = "Insufficient seller security deposit for offer " + request.offerId + ". Expected at least " + Restrictions.MIN_SECURITY_DEPOSIT_PCT + " but got " + offer.getSellerSecurityDepositPct(); + if (offer.getSellerSecurityDepositPct() < Restrictions.getMinSecurityDepositPct()) { + errorMessage = "Insufficient seller security deposit for offer " + request.offerId + ". Expected at least " + Restrictions.getMinSecurityDepositPct() + " but got " + offer.getSellerSecurityDepositPct(); log.warn(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; } // verify buyer's security deposit - if (offer.getBuyerSecurityDepositPct() < Restrictions.MIN_SECURITY_DEPOSIT_PCT) { - errorMessage = "Insufficient buyer security deposit for offer " + request.offerId + ". Expected at least " + Restrictions.MIN_SECURITY_DEPOSIT_PCT + " but got " + offer.getBuyerSecurityDepositPct(); + if (offer.getBuyerSecurityDepositPct() < Restrictions.getMinSecurityDepositPct()) { + errorMessage = "Insufficient buyer security deposit for offer " + request.offerId + ". Expected at least " + Restrictions.getMinSecurityDepositPct() + " but got " + offer.getBuyerSecurityDepositPct(); log.warn(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; diff --git a/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java b/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java index 4545a4e210..f2c047f5c8 100644 --- a/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java @@ -59,7 +59,7 @@ public class SecurityDepositValidator extends NumberValidator { private ValidationResult validateIfNotTooLowPercentageValue(String input) { try { double percentage = ParsingUtils.parsePercentStringToDouble(input); - double minPercentage = Restrictions.getMinSecurityDepositAsPercent(); + double minPercentage = Restrictions.getMinSecurityDepositPct(); if (percentage < minPercentage) return new ValidationResult(false, Res.get("validation.inputTooSmall", FormattingUtils.formatToPercentWithSymbol(minPercentage))); @@ -73,7 +73,7 @@ public class SecurityDepositValidator extends NumberValidator { private ValidationResult validateIfNotTooHighPercentageValue(String input) { try { double percentage = ParsingUtils.parsePercentStringToDouble(input); - double maxPercentage = Restrictions.getMaxSecurityDepositAsPercent(); + double maxPercentage = Restrictions.getMaxSecurityDepositPct(); if (percentage > maxPercentage) return new ValidationResult(false, Res.get("validation.inputTooLarge", FormattingUtils.formatToPercentWithSymbol(maxPercentage))); diff --git a/core/src/main/java/haveno/core/user/Preferences.java b/core/src/main/java/haveno/core/user/Preferences.java index 85f49195e1..cf074d395b 100644 --- a/core/src/main/java/haveno/core/user/Preferences.java +++ b/core/src/main/java/haveno/core/user/Preferences.java @@ -623,8 +623,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid } public void setSecurityDepositAsPercent(double securityDepositAsPercent, PaymentAccount paymentAccount) { - double max = Restrictions.getMaxSecurityDepositAsPercent(); - double min = Restrictions.getMinSecurityDepositAsPercent(); + double max = Restrictions.getMaxSecurityDepositPct(); + double min = Restrictions.getMinSecurityDepositPct(); if (PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount)) prefPayload.setSecurityDepositAsPercentForCrypto(Math.min(max, Math.max(min, securityDepositAsPercent))); @@ -853,12 +853,12 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid double value = PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount) ? prefPayload.getSecurityDepositAsPercentForCrypto() : prefPayload.getSecurityDepositAsPercent(); - if (value < Restrictions.getMinSecurityDepositAsPercent()) { - value = Restrictions.getMinSecurityDepositAsPercent(); + if (value < Restrictions.getMinSecurityDepositPct()) { + value = Restrictions.getMinSecurityDepositPct(); setSecurityDepositAsPercent(value, paymentAccount); } - return value == 0 ? Restrictions.getDefaultSecurityDepositAsPercent() : value; + return value == 0 ? Restrictions.getDefaultSecurityDepositPct() : value; } @Override diff --git a/core/src/main/java/haveno/core/user/PreferencesPayload.java b/core/src/main/java/haveno/core/user/PreferencesPayload.java index 35739037c1..31ed1e1880 100644 --- a/core/src/main/java/haveno/core/user/PreferencesPayload.java +++ b/core/src/main/java/haveno/core/user/PreferencesPayload.java @@ -41,7 +41,7 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import static haveno.core.xmr.wallet.Restrictions.getDefaultSecurityDepositAsPercent; +import static haveno.core.xmr.wallet.Restrictions.getDefaultSecurityDepositPct; @Slf4j @Data @@ -120,10 +120,10 @@ public final class PreferencesPayload implements PersistableEnvelope { private String rpcPw; @Nullable private String takeOfferSelectedPaymentAccountId; - private double securityDepositAsPercent = getDefaultSecurityDepositAsPercent(); + private double securityDepositAsPercent = getDefaultSecurityDepositPct(); private int ignoreDustThreshold = 600; private int clearDataAfterDays = Preferences.CLEAR_DATA_AFTER_DAYS_DEFAULT; - private double securityDepositAsPercentForCrypto = getDefaultSecurityDepositAsPercent(); + private double securityDepositAsPercentForCrypto = getDefaultSecurityDepositPct(); private int blockNotifyPort; private boolean tacAcceptedV120; private double bsqAverageTrimThreshold = 0.05; diff --git a/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java b/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java index 5cd181a4aa..3fa7410617 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java +++ b/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java @@ -26,12 +26,12 @@ import java.math.BigInteger; public class Restrictions { // configure restrictions - public static final double MIN_SECURITY_DEPOSIT_PCT = 0.15; - public static final double MAX_SECURITY_DEPOSIT_PCT = 0.5; - public static BigInteger MIN_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(0.1); - public static BigInteger MIN_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.1); - public static int MAX_EXTRA_INFO_LENGTH = 1500; - public static int MAX_OFFERS_WITH_SHARED_FUNDS = 10; + private static final double MIN_SECURITY_DEPOSIT_PCT = 0.15; + private static final double MAX_SECURITY_DEPOSIT_PCT = 0.5; + private static final BigInteger MIN_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(0.05); + private static final BigInteger MIN_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.1); + private static final int MAX_EXTRA_INFO_LENGTH = 1500; + private static final int MAX_OFFERS_WITH_SHARED_FUNDS = 10; // At mediation we require a min. payout to the losing party to keep incentive for the trader to accept the // mediated payout. For Refund agent cases we do not have that restriction. @@ -57,15 +57,15 @@ public class Restrictions { return MIN_TRADE_AMOUNT; } - public static double getDefaultSecurityDepositAsPercent() { + public static double getDefaultSecurityDepositPct() { return MIN_SECURITY_DEPOSIT_PCT; } - public static double getMinSecurityDepositAsPercent() { + public static double getMinSecurityDepositPct() { return MIN_SECURITY_DEPOSIT_PCT; } - public static double getMaxSecurityDepositAsPercent() { + public static double getMaxSecurityDepositPct() { return MAX_SECURITY_DEPOSIT_PCT; } @@ -73,6 +73,14 @@ public class Restrictions { return MIN_SECURITY_DEPOSIT; } + public static int getMaxExtraInfoLength() { + return MAX_EXTRA_INFO_LENGTH; + } + + public static int getMaxOffersWithSharedFunds() { + return MAX_OFFERS_WITH_SHARED_FUNDS; + } + // This value must be lower than MIN_BUYER_SECURITY_DEPOSIT and SELLER_SECURITY_DEPOSIT public static BigInteger getMinRefundAtMediatedDispute() { if (MIN_REFUND_AT_MEDIATED_DISPUTE == null) diff --git a/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java b/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java index f14f41afdc..f6da1dfd4c 100644 --- a/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java +++ b/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java @@ -76,11 +76,11 @@ public class CoinUtilTest { BigInteger result = CoinUtil.getAdjustedAmount( HavenoUtils.xmrToAtomicUnits(0.1), Price.valueOf("USD", 1000_0000), - HavenoUtils.xmrToAtomicUnits(0.1), + Restrictions.getMinTradeAmount(), HavenoUtils.xmrToAtomicUnits(0.2), 1); assertEquals( - HavenoUtils.formatXmr(Restrictions.MIN_TRADE_AMOUNT, true), + HavenoUtils.formatXmr(Restrictions.getMinTradeAmount(), true), HavenoUtils.formatXmr(result, true), "Minimum trade amount allowed should be adjusted to the smallest trade allowed." ); @@ -95,7 +95,7 @@ public class CoinUtilTest { fail("Expected IllegalArgumentException to be thrown when amount is too low."); } catch (IllegalArgumentException iae) { assertEquals( - "amount must be above minimum of 0.1 xmr but was 0.0 xmr", + "amount must be above minimum of 0.05 xmr but was 0.0 xmr", iae.getMessage(), "Unexpected exception message." ); @@ -104,11 +104,11 @@ public class CoinUtilTest { result = CoinUtil.getAdjustedAmount( HavenoUtils.xmrToAtomicUnits(0.1), Price.valueOf("USD", 1000_0000), - HavenoUtils.xmrToAtomicUnits(0.1), + Restrictions.getMinTradeAmount(), HavenoUtils.xmrToAtomicUnits(0.2), 1); assertEquals( - "0.10 XMR", + "0.05 XMR", HavenoUtils.formatXmr(result, true), "Minimum allowed trade amount should not be adjusted." ); @@ -116,11 +116,11 @@ public class CoinUtilTest { result = CoinUtil.getAdjustedAmount( HavenoUtils.xmrToAtomicUnits(0.1), Price.valueOf("USD", 1000_0000), - HavenoUtils.xmrToAtomicUnits(0.1), + Restrictions.getMinTradeAmount(), HavenoUtils.xmrToAtomicUnits(0.25), 1); assertEquals( - "0.10 XMR", + "0.05 XMR", HavenoUtils.formatXmr(result, true), "Minimum trade amount allowed should respect maxTradeLimit and factor, if possible." ); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java index b8bbdcbd41..fa286767b8 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java @@ -168,7 +168,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { reserveExactAmount = preferences.getSplitOfferOutput(); useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice()); - securityDepositPct.set(Restrictions.getMinSecurityDepositAsPercent()); + securityDepositPct.set(Restrictions.getMinSecurityDepositPct()); paymentAccountsChangeListener = change -> fillPaymentAccounts(); } @@ -338,7 +338,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { } private void setSuggestedSecurityDeposit(PaymentAccount paymentAccount) { - var minSecurityDeposit = Restrictions.getMinSecurityDepositAsPercent(); + var minSecurityDeposit = Restrictions.getMinSecurityDepositPct(); try { if (getTradeCurrency() == null) { setSecurityDepositPct(minSecurityDeposit); @@ -369,7 +369,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { } // Suggested deposit is double the trade range over the previous lock time period, bounded by min/max deposit var suggestedSecurityDeposit = - Math.min(2 * (max - min) / max, Restrictions.getMaxSecurityDepositAsPercent()); + Math.min(2 * (max - min) / max, Restrictions.getMaxSecurityDepositPct()); securityDepositPct.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit)); } catch (Throwable t) { log.error(t.toString()); @@ -472,14 +472,14 @@ public abstract class MutableOfferDataModel extends OfferDataModel { return marketPriceMarginPct; } - BigInteger getMaxTradeLimit() { - return offerUtil.getMaxTradeLimitForRelease(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get()); - } - BigInteger getMinTradeLimit() { return Restrictions.getMinTradeAmount(); } + BigInteger getMaxTradeLimit() { + return offerUtil.getMaxTradeLimitForRelease(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get()); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Utils /////////////////////////////////////////////////////////////////////////////////////////// @@ -537,10 +537,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel { // if the volume != amount * price, we need to adjust the amount if (amount.get() == null || !volumeBefore.equals(price.get().getVolumeByAmount(amount.get()))) { BigInteger value = price.get().getAmountByVolume(volumeBefore); + BigInteger minAmount = getMinTradeLimit(); BigInteger maxAmount = getMaxTradeLimit(); - BigInteger minAmount = Restrictions.getMinTradeAmount(); - value = value.min(maxAmount); // adjust if above maximum value = value.max(minAmount); // adjust if below minimum + value = value.min(maxAmount); // adjust if above maximum value = CoinUtil.getRoundedAmount(value, price.get(), minAmount, maxAmount, tradeCurrencyCode.get(), paymentAccount.getPaymentMethod().getId()); amount.set(value); } @@ -689,7 +689,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { double offerSellerSecurityDepositAsPercent = CoinUtil.getAsPercentPerXmr(offerSellerSecurityDeposit, offer.getAmount()); return Math.min(offerSellerSecurityDepositAsPercent, - Restrictions.getMaxSecurityDepositAsPercent()); + Restrictions.getMaxSecurityDepositPct()); } ReadOnlyObjectProperty totalToPayAsProperty() { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java index 1c396f202a..96c083cb73 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java @@ -483,6 +483,7 @@ public abstract class MutableOfferViewModel ext buyerAsTakerWithoutDepositListener = (ov, oldValue, newValue) -> { if (dataModel.paymentAccount != null) xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get())); xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit()); + xmrValidator.setMinValue(dataModel.getMinTradeLimit()); if (amount.get() != null) amountValidationResult.set(isXmrInputValid(amount.get())); updateSecurityDeposit(); setSecurityDepositToModel(); @@ -601,7 +602,7 @@ public abstract class MutableOfferViewModel ext if (dataModel.paymentAccount != null) xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get())); xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit()); - xmrValidator.setMinValue(Restrictions.getMinTradeAmount()); + xmrValidator.setMinValue(dataModel.getMinTradeLimit()); final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY; @@ -741,7 +742,7 @@ public abstract class MutableOfferViewModel ext if (minAmount.get() != null) minAmountValidationResult.set(isXmrInputValid(minAmount.get())); } else if (amount.get() != null && xmrValidator.getMaxTradeLimit() != null && xmrValidator.getMaxTradeLimit().longValueExact() == OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact()) { - if (ParsingUtils.parseNumberStringToDouble(amount.get()) < HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount())) { + if (ParsingUtils.parseNumberStringToDouble(amount.get()) < HavenoUtils.atomicUnitsToXmr(dataModel.getMinTradeLimit())) { amountValidationResult.set(result); } else { amount.set(HavenoUtils.formatXmr(xmrValidator.getMaxTradeLimit())); @@ -980,7 +981,7 @@ public abstract class MutableOfferViewModel ext InputValidator.ValidationResult result = securityDepositValidator.validate(securityDeposit.get()); securityDepositValidationResult.set(result); if (result.isValid) { - double defaultSecurityDeposit = Restrictions.getDefaultSecurityDepositAsPercent(); + double defaultSecurityDeposit = Restrictions.getDefaultSecurityDepositPct(); String key = "buyerSecurityDepositIsLowerAsDefault"; double depositAsDouble = ParsingUtils.parsePercentStringToDouble(securityDeposit.get()); if (preferences.showAgain(key) && depositAsDouble < defaultSecurityDeposit) { @@ -1167,10 +1168,9 @@ public abstract class MutableOfferViewModel ext if (amount.get() != null && !amount.get().isEmpty()) { BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter)); - BigInteger maxTradeLimit = dataModel.getMaxTradeLimit(); Price price = dataModel.getPrice().get(); if (price != null && price.isPositive()) { - amount = CoinUtil.getRoundedAmount(amount, price, dataModel.getMinAmount().get(), maxTradeLimit, tradeCurrencyCode.get(), dataModel.getPaymentAccount().getPaymentMethod().getId()); + amount = CoinUtil.getRoundedAmount(amount, price, dataModel.getMinTradeLimit(), dataModel.getMaxTradeLimit(), tradeCurrencyCode.get(), dataModel.getPaymentAccount().getPaymentMethod().getId()); } dataModel.setAmount(amount); if (syncMinAmountWithAmount || @@ -1227,7 +1227,7 @@ public abstract class MutableOfferViewModel ext if (securityDeposit.get() != null && !securityDeposit.get().isEmpty() && !isMinSecurityDeposit.get()) { dataModel.setSecurityDepositPct(ParsingUtils.parsePercentStringToDouble(securityDeposit.get())); } else { - dataModel.setSecurityDepositPct(Restrictions.getDefaultSecurityDepositAsPercent()); + dataModel.setSecurityDepositPct(Restrictions.getDefaultSecurityDepositPct()); } } @@ -1243,7 +1243,7 @@ public abstract class MutableOfferViewModel ext // If the security deposit in the model is not valid percent String value = FormattingUtils.formatToPercent(dataModel.getSecurityDepositPct().get()); if (!securityDepositValidator.validate(value).isValid) { - dataModel.setSecurityDepositPct(Restrictions.getDefaultSecurityDepositAsPercent()); + dataModel.setSecurityDepositPct(Restrictions.getDefaultSecurityDepositPct()); } } @@ -1299,7 +1299,7 @@ public abstract class MutableOfferViewModel ext } else { boolean hasBuyerAsTakerWithoutDeposit = dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer(); securityDeposit.set(FormattingUtils.formatToPercent(hasBuyerAsTakerWithoutDeposit ? - Restrictions.getDefaultSecurityDepositAsPercent() : // use default percent if no deposit from buyer + Restrictions.getDefaultSecurityDepositPct() : // use default percent if no deposit from buyer dataModel.getSecurityDepositPct().get())); } } @@ -1333,8 +1333,8 @@ public abstract class MutableOfferViewModel ext } private ValidationResult getExtraInfoValidationResult() { - if (extraInfo.get() != null && !extraInfo.get().isEmpty() && extraInfo.get().length() > Restrictions.MAX_EXTRA_INFO_LENGTH) { - return new InputValidator.ValidationResult(false, Res.get("createOffer.extraInfo.invalid.tooLong", Restrictions.MAX_EXTRA_INFO_LENGTH)); + if (extraInfo.get() != null && !extraInfo.get().isEmpty() && extraInfo.get().length() > Restrictions.getMaxExtraInfoLength()) { + return new InputValidator.ValidationResult(false, Res.get("createOffer.extraInfo.invalid.tooLong", Restrictions.getMaxExtraInfoLength())); } else { return new InputValidator.ValidationResult(true); } diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java index 1795637ee9..254f5b6fa2 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java @@ -130,9 +130,9 @@ class EditOfferDataModel extends MutableOfferDataModel { // by percentage than the restriction. We can't determine the percentage originally entered at offer // creation, so just use the default value as it doesn't matter anyway. double securityDepositPercent = CoinUtil.getAsPercentPerXmr(offer.getMaxSellerSecurityDeposit(), offer.getAmount()); - if (securityDepositPercent > Restrictions.getMaxSecurityDepositAsPercent() + if (securityDepositPercent > Restrictions.getMaxSecurityDepositPct() && offer.getMaxSellerSecurityDeposit().equals(Restrictions.getMinSecurityDeposit())) - securityDepositPct.set(Restrictions.getDefaultSecurityDepositAsPercent()); + securityDepositPct.set(Restrictions.getDefaultSecurityDepositPct()); else securityDepositPct.set(securityDepositPercent);