limit offer extra info to 1500 characters

This commit is contained in:
woodser 2025-03-22 07:57:31 -04:00 committed by GitHub
parent ce27818f43
commit 1a2dcfc704
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 195 additions and 30 deletions

View file

@ -1396,6 +1396,14 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
return; return;
} }
// 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();
log.warn(errorMessage);
sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage);
return;
}
// verify the trade protocol version // verify the trade protocol version
if (request.getOfferPayload().getProtocolVersion() != Version.TRADE_PROTOCOL_VERSION) { if (request.getOfferPayload().getProtocolVersion() != Version.TRADE_PROTOCOL_VERSION) {
errorMessage = "Unsupported protocol version: " + request.getOfferPayload().getProtocolVersion(); errorMessage = "Unsupported protocol version: " + request.getOfferPayload().getProtocolVersion();

View file

@ -30,6 +30,7 @@ public class Restrictions {
public static final double MAX_SECURITY_DEPOSIT_PCT = 0.5; public static final double MAX_SECURITY_DEPOSIT_PCT = 0.5;
public static BigInteger MIN_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(0.1); public static BigInteger MIN_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(0.1);
public static BigInteger MIN_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.1); public static BigInteger MIN_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.1);
public static int MAX_EXTRA_INFO_LENGTH = 1500;
// At mediation we require a min. payout to the losing party to keep incentive for the trader to accept the // 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. // mediated payout. For Refund agent cases we do not have that restriction.

View file

@ -495,6 +495,7 @@ createOffer.triggerPrice.tooltip=As protection against drastic price movements y
deactivates the offer if the market price reaches that value. deactivates the offer if the market price reaches that value.
createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0} createOffer.triggerPrice.invalid.tooLow=Value must be higher than {0}
createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0} createOffer.triggerPrice.invalid.tooHigh=Value must be lower than {0}
createOffer.extraInfo.invalid.tooLong=Must not exceed {0} characters.
# new entries # new entries
createOffer.placeOfferButton=Review: Place offer to {0} monero createOffer.placeOfferButton=Review: Place offer to {0} monero

View file

@ -0,0 +1,140 @@
/*
* This file is part of Haveno.
*
* Haveno 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.
*
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
*/
package haveno.desktop.components;
import com.jfoenix.controls.JFXTextArea;
import haveno.core.util.validation.InputValidator;
import haveno.desktop.util.validation.JFXInputValidator;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Skin;
/**
* TextArea with validation support.
* If validator is set it supports on focus out validation with that validator. If a more sophisticated validation is
* needed the validationResultProperty can be used for applying validation result done by external validation.
* In case the isValid property in validationResultProperty get set to false we display a red border and an error
* message within the errorMessageDisplay placed on the right of the text area.
* The errorMessageDisplay gets closed when the ValidatingTextArea instance gets removed from the scene graph or when
* hideErrorMessageDisplay() is called.
* There can be only 1 errorMessageDisplays at a time we use static field for it.
* The position is derived from the position of the textArea itself or if set from the layoutReference node.
*/
//TODO There are some rare situation where it behaves buggy. Needs further investigation and improvements.
public class InputTextArea extends JFXTextArea {
private final ObjectProperty<InputValidator.ValidationResult> validationResult = new SimpleObjectProperty<>
(new InputValidator.ValidationResult(true));
private final JFXInputValidator jfxValidationWrapper = new JFXInputValidator();
private InputValidator validator;
private String errorMessage = null;
public InputValidator getValidator() {
return validator;
}
public void setValidator(InputValidator validator) {
this.validator = validator;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public InputTextArea() {
super();
getValidators().add(jfxValidationWrapper);
validationResult.addListener((ov, oldValue, newValue) -> {
if (newValue != null) {
jfxValidationWrapper.resetValidation();
if (!newValue.isValid) {
if (!newValue.errorMessageEquals(oldValue)) { // avoid blinking
validate(); // ensure that the new error message replaces the old one
}
if (this.errorMessage != null) {
jfxValidationWrapper.applyErrorMessage(this.errorMessage);
} else {
jfxValidationWrapper.applyErrorMessage(newValue);
}
}
validate();
}
});
textProperty().addListener((o, oldValue, newValue) -> {
refreshValidation();
});
focusedProperty().addListener((o, oldValue, newValue) -> {
if (validator != null) {
if (!oldValue && newValue) {
this.validationResult.set(new InputValidator.ValidationResult(true));
} else {
this.validationResult.set(validator.validate(getText()));
}
}
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
public void resetValidation() {
jfxValidationWrapper.resetValidation();
String input = getText();
if (input.isEmpty()) {
validationResult.set(new InputValidator.ValidationResult(true));
} else {
validationResult.set(validator.validate(input));
}
}
public void refreshValidation() {
if (validator != null) {
this.validationResult.set(validator.validate(getText()));
}
}
public void setInvalid(String message) {
validationResult.set(new InputValidator.ValidationResult(false, message));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public ObjectProperty<InputValidator.ValidationResult> validationResultProperty() {
return validationResult;
}
protected Skin<?> createDefaultSkin() {
return new JFXTextAreaSkinHavenoStyle(this);
}
}

View file

@ -501,15 +501,15 @@ tree-table-view:focused {
-jfx-default-color: -bs-color-primary; -jfx-default-color: -bs-color-primary;
} }
.jfx-date-picker .jfx-text-field { .jfx-date-picker .jfx-text-field .jfx-text-area {
-fx-padding: 0.333333em 0em 0.333333em 0em; -fx-padding: 0.333333em 0em 0.333333em 0em;
} }
.jfx-date-picker .jfx-text-field > .input-line { .jfx-date-picker .jfx-text-field .jfx-text-area > .input-line {
-fx-translate-x: 0em; -fx-translate-x: 0em;
} }
.jfx-date-picker .jfx-text-field > .input-focused-line { .jfx-date-picker .jfx-text-field .jfx-text-area > .input-focused-line {
-fx-translate-x: 0em; -fx-translate-x: 0em;
} }

View file

@ -44,8 +44,8 @@ import haveno.desktop.components.AutoTooltipLabel;
import haveno.desktop.components.BalanceTextField; import haveno.desktop.components.BalanceTextField;
import haveno.desktop.components.BusyAnimation; import haveno.desktop.components.BusyAnimation;
import haveno.desktop.components.FundsTextField; import haveno.desktop.components.FundsTextField;
import haveno.desktop.components.HavenoTextArea;
import haveno.desktop.components.InfoInputTextField; import haveno.desktop.components.InfoInputTextField;
import haveno.desktop.components.InputTextArea;
import haveno.desktop.components.InputTextField; import haveno.desktop.components.InputTextField;
import haveno.desktop.components.TitledGroupBg; import haveno.desktop.components.TitledGroupBg;
import haveno.desktop.main.MainView; import haveno.desktop.main.MainView;
@ -76,7 +76,6 @@ import javafx.scene.control.ComboBox;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.control.Separator; import javafx.scene.control.Separator;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleButton;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
@ -140,7 +139,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
private BalanceTextField balanceTextField; private BalanceTextField balanceTextField;
private ToggleButton reserveExactAmountSlider; private ToggleButton reserveExactAmountSlider;
private ToggleButton buyerAsTakerWithoutDepositSlider; private ToggleButton buyerAsTakerWithoutDepositSlider;
protected TextArea extraInfoTextArea; protected InputTextArea extraInfoTextArea;
private FundsTextField totalToPayTextField; private FundsTextField totalToPayTextField;
private Label amountDescriptionLabel, priceCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel, private Label amountDescriptionLabel, priceCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel,
waitingForFundsLabel, marketBasedPriceLabel, percentagePriceDescriptionLabel, tradeFeeDescriptionLabel, waitingForFundsLabel, marketBasedPriceLabel, percentagePriceDescriptionLabel, tradeFeeDescriptionLabel,
@ -211,7 +210,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
createListeners(); createListeners();
balanceTextField.setFormatter(model.getBtcFormatter()); balanceTextField.setFormatter(model.getXmrFormatter());
paymentAccountsComboBox.setConverter(GUIUtil.getPaymentAccountsComboBoxStringConverter()); paymentAccountsComboBox.setConverter(GUIUtil.getPaymentAccountsComboBoxStringConverter());
paymentAccountsComboBox.setButtonCell(GUIUtil.getComboBoxButtonCell(Res.get("shared.chooseTradingAccount"), paymentAccountsComboBox.setButtonCell(GUIUtil.getComboBoxButtonCell(Res.get("shared.chooseTradingAccount"),
@ -592,6 +591,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
triggerPriceInputTextField.validationResultProperty().bind(model.triggerPriceValidationResult); triggerPriceInputTextField.validationResultProperty().bind(model.triggerPriceValidationResult);
volumeTextField.validationResultProperty().bind(model.volumeValidationResult); volumeTextField.validationResultProperty().bind(model.volumeValidationResult);
securityDepositInputTextField.validationResultProperty().bind(model.securityDepositValidationResult); securityDepositInputTextField.validationResultProperty().bind(model.securityDepositValidationResult);
extraInfoTextArea.validationResultProperty().bind(model.extraInfoValidationResult);
// funding // funding
fundingHBox.visibleProperty().bind(model.getDataModel().getIsXmrWalletFunded().not().and(model.showPayFundsScreenDisplayed)); fundingHBox.visibleProperty().bind(model.getDataModel().getIsXmrWalletFunded().not().and(model.showPayFundsScreenDisplayed));
@ -713,7 +713,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
triggerPriceInputTextField.setText(model.triggerPrice.get()); triggerPriceInputTextField.setText(model.triggerPrice.get());
}; };
extraInfoFocusedListener = (observable, oldValue, newValue) -> { extraInfoFocusedListener = (observable, oldValue, newValue) -> {
model.onFocusOutExtraInfoTextField(oldValue, newValue); model.onFocusOutExtraInfoTextArea(oldValue, newValue);
extraInfoTextArea.setText(model.extraInfo.get()); extraInfoTextArea.setText(model.extraInfo.get());
}; };
@ -1097,7 +1097,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
Res.get("payment.shared.optionalExtra"), 25 + heightAdjustment); Res.get("payment.shared.optionalExtra"), 25 + heightAdjustment);
GridPane.setColumnSpan(extraInfoTitledGroupBg, 3); GridPane.setColumnSpan(extraInfoTitledGroupBg, 3);
extraInfoTextArea = new HavenoTextArea(); extraInfoTextArea = new InputTextArea();
extraInfoTextArea.setPromptText(Res.get("payment.shared.extraInfo.prompt.offer")); extraInfoTextArea.setPromptText(Res.get("payment.shared.extraInfo.prompt.offer"));
extraInfoTextArea.getStyleClass().add("text-area"); extraInfoTextArea.getStyleClass().add("text-area");
extraInfoTextArea.setWrapText(true); extraInfoTextArea.setWrapText(true);
@ -1109,7 +1109,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
GridPane.setColumnSpan(extraInfoTextArea, GridPane.REMAINING); GridPane.setColumnSpan(extraInfoTextArea, GridPane.REMAINING);
GridPane.setColumnIndex(extraInfoTextArea, 0); GridPane.setColumnIndex(extraInfoTextArea, 0);
GridPane.setHalignment(extraInfoTextArea, HPos.LEFT); GridPane.setHalignment(extraInfoTextArea, HPos.LEFT);
GridPane.setMargin(extraInfoTextArea, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0)); GridPane.setMargin(extraInfoTextArea, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 10, 0));
gridPane.getChildren().add(extraInfoTextArea); gridPane.getChildren().add(extraInfoTextArea);
} }

View file

@ -99,7 +99,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final Navigation navigation; private final Navigation navigation;
private final Preferences preferences; private final Preferences preferences;
protected final CoinFormatter btcFormatter; protected final CoinFormatter xmrFormatter;
private final FiatVolumeValidator fiatVolumeValidator; private final FiatVolumeValidator fiatVolumeValidator;
private final AmountValidator4Decimals amountValidator4Decimals; private final AmountValidator4Decimals amountValidator4Decimals;
private final AmountValidator8Decimals amountValidator8Decimals; private final AmountValidator8Decimals amountValidator8Decimals;
@ -160,6 +160,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
final ObjectProperty<InputValidator.ValidationResult> triggerPriceValidationResult = new SimpleObjectProperty<>(new InputValidator.ValidationResult(true)); final ObjectProperty<InputValidator.ValidationResult> triggerPriceValidationResult = new SimpleObjectProperty<>(new InputValidator.ValidationResult(true));
final ObjectProperty<InputValidator.ValidationResult> volumeValidationResult = new SimpleObjectProperty<>(); final ObjectProperty<InputValidator.ValidationResult> volumeValidationResult = new SimpleObjectProperty<>();
final ObjectProperty<InputValidator.ValidationResult> securityDepositValidationResult = new SimpleObjectProperty<>(); final ObjectProperty<InputValidator.ValidationResult> securityDepositValidationResult = new SimpleObjectProperty<>();
final ObjectProperty<InputValidator.ValidationResult> extraInfoValidationResult = new SimpleObjectProperty<>();
private ChangeListener<String> amountStringListener; private ChangeListener<String> amountStringListener;
private ChangeListener<String> minAmountStringListener; private ChangeListener<String> minAmountStringListener;
@ -195,26 +196,26 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
FiatVolumeValidator fiatVolumeValidator, FiatVolumeValidator fiatVolumeValidator,
AmountValidator4Decimals amountValidator4Decimals, AmountValidator4Decimals amountValidator4Decimals,
AmountValidator8Decimals amountValidator8Decimals, AmountValidator8Decimals amountValidator8Decimals,
XmrValidator btcValidator, XmrValidator xmrValidator,
SecurityDepositValidator securityDepositValidator, SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService, PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
Navigation navigation, Navigation navigation,
Preferences preferences, Preferences preferences,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter xmrFormatter,
OfferUtil offerUtil) { OfferUtil offerUtil) {
super(dataModel); super(dataModel);
this.fiatVolumeValidator = fiatVolumeValidator; this.fiatVolumeValidator = fiatVolumeValidator;
this.amountValidator4Decimals = amountValidator4Decimals; this.amountValidator4Decimals = amountValidator4Decimals;
this.amountValidator8Decimals = amountValidator8Decimals; this.amountValidator8Decimals = amountValidator8Decimals;
this.xmrValidator = btcValidator; this.xmrValidator = xmrValidator;
this.securityDepositValidator = securityDepositValidator; this.securityDepositValidator = securityDepositValidator;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.navigation = navigation; this.navigation = navigation;
this.preferences = preferences; this.preferences = preferences;
this.btcFormatter = btcFormatter; this.xmrFormatter = xmrFormatter;
this.offerUtil = offerUtil; this.offerUtil = offerUtil;
paymentLabel = Res.get("createOffer.fundsBox.paymentLabel", dataModel.shortOfferId); paymentLabel = Res.get("createOffer.fundsBox.paymentLabel", dataModel.shortOfferId);
@ -500,11 +501,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
}; };
extraInfoStringListener = (ov, oldValue, newValue) -> { extraInfoStringListener = (ov, oldValue, newValue) -> {
if (newValue != null) { onExtraInfoTextAreaChanged();
extraInfo.set(newValue);
} else {
extraInfo.set("");
}
}; };
isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState(); isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState();
@ -531,7 +528,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
tradeFee.set(HavenoUtils.formatXmr(makerFee)); tradeFee.set(HavenoUtils.formatXmr(makerFee));
tradeFeeInXmrWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, tradeFeeInXmrWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
dataModel.getMaxMakerFee(), dataModel.getMaxMakerFee(),
btcFormatter)); xmrFormatter));
} }
@ -836,8 +833,16 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
} }
} }
public void onFocusOutExtraInfoTextField(boolean oldValue, boolean newValue) { public void onFocusOutExtraInfoTextArea(boolean oldValue, boolean newValue) {
if (oldValue && !newValue) { if (oldValue && !newValue) {
onExtraInfoTextAreaChanged();
}
}
public void onExtraInfoTextAreaChanged() {
extraInfoValidationResult.set(getExtraInfoValidationResult());
updateButtonDisableState();
if (extraInfoValidationResult.get().isValid) {
dataModel.setExtraInfo(extraInfo.get()); dataModel.setExtraInfo(extraInfo.get());
} }
} }
@ -1045,8 +1050,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
.show(); .show();
} }
CoinFormatter getBtcFormatter() { CoinFormatter getXmrFormatter() {
return btcFormatter; return xmrFormatter;
} }
public boolean isShownAsBuyOffer() { public boolean isShownAsBuyOffer() {
@ -1064,7 +1069,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
public String getTradeAmount() { public String getTradeAmount() {
return OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, return OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
dataModel.getAmount().get(), dataModel.getAmount().get(),
btcFormatter); xmrFormatter);
} }
public String getSecurityDepositLabel() { public String getSecurityDepositLabel() {
@ -1084,7 +1089,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil,
dataModel.getSecurityDeposit(), dataModel.getSecurityDeposit(),
dataModel.getAmount().get(), dataModel.getAmount().get(),
btcFormatter xmrFormatter
); );
} }
@ -1097,7 +1102,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil,
dataModel.getMaxMakerFee(), dataModel.getMaxMakerFee(),
dataModel.getAmount().get(), dataModel.getAmount().get(),
btcFormatter); xmrFormatter);
} }
public String getMakerFeePercentage() { public String getMakerFeePercentage() {
@ -1108,7 +1113,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
public String getTotalToPayInfo() { public String getTotalToPayInfo() {
return OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, return OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil,
dataModel.totalToPay.get(), dataModel.totalToPay.get(),
btcFormatter); xmrFormatter);
} }
public String getFundsStructure() { public String getFundsStructure() {
@ -1181,7 +1186,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void setAmountToModel() { private void setAmountToModel() {
if (amount.get() != null && !amount.get().isEmpty()) { if (amount.get() != null && !amount.get().isEmpty()) {
BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), btcFormatter)); BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter));
long maxTradeLimit = dataModel.getMaxTradeLimit(); long maxTradeLimit = dataModel.getMaxTradeLimit();
Price price = dataModel.getPrice().get(); Price price = dataModel.getPrice().get();
@ -1202,7 +1207,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private void setMinAmountToModel() { private void setMinAmountToModel() {
if (minAmount.get() != null && !minAmount.get().isEmpty()) { if (minAmount.get() != null && !minAmount.get().isEmpty()) {
BigInteger minAmount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), btcFormatter)); BigInteger minAmount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), xmrFormatter));
Price price = dataModel.getPrice().get(); Price price = dataModel.getPrice().get();
long maxTradeLimit = dataModel.getMaxTradeLimit(); long maxTradeLimit = dataModel.getMaxTradeLimit();
@ -1343,10 +1348,20 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
inputDataValid = inputDataValid && securityDepositValidator.validate(securityDeposit.get()).isValid; inputDataValid = inputDataValid && securityDepositValidator.validate(securityDeposit.get()).isValid;
} }
inputDataValid = inputDataValid && getExtraInfoValidationResult().isValid;
isNextButtonDisabled.set(!inputDataValid); isNextButtonDisabled.set(!inputDataValid);
isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || !dataModel.getIsXmrWalletFunded().get()); isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || !dataModel.getIsXmrWalletFunded().get());
} }
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));
} else {
return new InputValidator.ValidationResult(true);
}
}
private void updateMarketPriceToManual() { private void updateMarketPriceToManual() {
final String currencyCode = dataModel.getTradeCurrencyCode().get(); final String currencyCode = dataModel.getTradeCurrencyCode().get();
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);