Add adjustment fro multiple ofg 10 EUR for HalCash

With ATMs one can withdraw only multiples of 10 EUR.
We adjust the input values the way that the EUR amount leads to
multiple of 10. MinAmount and amount will be adjusted.

Please note that a similar approach like implemented here for HalCash
can be used for removing the decimal places from fiat amounts to
improve privacy. We keep that for a follow up PR to not mix 2 different
use cases.
This commit is contained in:
Manfred Karrer 2018-08-11 20:48:42 +02:00
parent e7b3629a71
commit 3bce2b828b
No known key found for this signature in database
GPG Key ID: 401250966A6B2C46
6 changed files with 70 additions and 21 deletions

View File

@ -40,6 +40,7 @@ import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.BankAccount; import bisq.core.payment.BankAccount;
import bisq.core.payment.CountryBasedPaymentAccount; import bisq.core.payment.CountryBasedPaymentAccount;
import bisq.core.payment.F2FAccount; import bisq.core.payment.F2FAccount;
import bisq.core.payment.HalCashAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.SameBankAccount; import bisq.core.payment.SameBankAccount;
import bisq.core.payment.SepaAccount; import bisq.core.payment.SepaAccount;
@ -307,7 +308,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
Offer createAndGetOffer() { Offer createAndGetOffer() {
final boolean useMarketBasedPriceValue = isUseMarketBasedPriceValue(); boolean useMarketBasedPriceValue = isUseMarketBasedPriceValue();
long priceAsLong = price.get() != null && !useMarketBasedPriceValue ? price.get().getValue() : 0L; long priceAsLong = price.get() != null && !useMarketBasedPriceValue ? price.get().getValue() : 0L;
String currencyCode = tradeCurrencyCode.get(); String currencyCode = tradeCurrencyCode.get();
boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode); boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode);
@ -662,7 +663,13 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
!amount.get().isZero() && !amount.get().isZero() &&
!price.get().isZero()) { !price.get().isZero()) {
try { try {
volume.set(price.get().getVolumeByAmount(amount.get())); Volume volumeByAmount = price.get().getVolumeByAmount(amount.get());
// For HalCash we want multiple of 10 EUR
if (isHalCashAccount())
volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount);
volume.set(volumeByAmount);
} catch (Throwable t) { } catch (Throwable t) {
log.error(t.toString()); log.error(t.toString());
} }
@ -743,7 +750,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
} }
protected boolean isUseMarketBasedPriceValue() { protected boolean isUseMarketBasedPriceValue() {
return marketPriceAvailable && useMarketBasedPrice.get(); return marketPriceAvailable && useMarketBasedPrice.get() && !isHalCashAccount();
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -813,4 +820,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
public boolean isBsqForFeeAvailable() { public boolean isBsqForFeeAvailable() {
return OfferUtil.isBsqForFeeAvailable(bsqWalletService, amount.get(), marketPriceAvailable, marketPriceMargin); return OfferUtil.isBsqForFeeAvailable(bsqWalletService, amount.get(), marketPriceAvailable, marketPriceMargin);
} }
public boolean isHalCashAccount() {
return paymentAccount instanceof HalCashAccount;
}
} }

View File

@ -238,7 +238,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
onPaymentAccountsComboBoxSelected(); onPaymentAccountsComboBoxSelected();
balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsCoinProperty().get()); balanceTextField.setTargetAmount(model.getDataModel().totalToPayAsCoinProperty().get());
updateMarketPriceAvailable(); updatePriceToggle();
} }
} }
@ -297,7 +297,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
percentagePriceDescription.setText(Res.get("shared.aboveInPercent")); percentagePriceDescription.setText(Res.get("shared.aboveInPercent"));
} }
updateMarketPriceAvailable(); updatePriceToggle();
if (!model.getDataModel().isMakerFeeValid() && model.getDataModel().getMakerFee() != null) if (!model.getDataModel().isMakerFeeValid() && model.getDataModel().getMakerFee() != null)
showInsufficientBsqFundsForBtcFeePaymentPopup(); showInsufficientBsqFundsForBtcFeePaymentPopup();
@ -502,6 +502,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
} }
currencyComboBox.setOnAction(currencyComboBoxSelectionHandler); currencyComboBox.setOnAction(currencyComboBoxSelectionHandler);
updatePriceToggle();
} }
private void onCurrencyComboBoxSelected() { private void onCurrencyComboBoxSelected() {
@ -703,7 +705,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
} }
}; };
marketPriceAvailableListener = (observable, oldValue, newValue) -> updateMarketPriceAvailable(); marketPriceAvailableListener = (observable, oldValue, newValue) -> updatePriceToggle();
getShowWalletFundedNotificationListener = (observable, oldValue, newValue) -> { getShowWalletFundedNotificationListener = (observable, oldValue, newValue) -> {
if (newValue) { if (newValue) {
@ -756,15 +758,16 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
return label; return label;
} }
protected void updateMarketPriceAvailable() { protected void updatePriceToggle() {
int marketPriceAvailableValue = model.marketPriceAvailableProperty.get(); int marketPriceAvailableValue = model.marketPriceAvailableProperty.get();
if (marketPriceAvailableValue > -1) { if (marketPriceAvailableValue > -1) {
boolean isMarketPriceAvailable = marketPriceAvailableValue == 1; boolean showPriceToggle = marketPriceAvailableValue == 1 &&
percentagePriceBox.setVisible(isMarketPriceAvailable); !model.getDataModel().isHalCashAccount();
percentagePriceBox.setManaged(isMarketPriceAvailable); percentagePriceBox.setVisible(showPriceToggle);
priceTypeToggleButton.setVisible(isMarketPriceAvailable); percentagePriceBox.setManaged(showPriceToggle);
priceTypeToggleButton.setManaged(isMarketPriceAvailable); priceTypeToggleButton.setVisible(showPriceToggle);
boolean fixedPriceSelected = !model.getDataModel().getUseMarketBasedPrice().get() || !isMarketPriceAvailable; priceTypeToggleButton.setManaged(showPriceToggle);
boolean fixedPriceSelected = !model.getDataModel().getUseMarketBasedPrice().get() || !showPriceToggle;
updatePriceToggleButtons(fixedPriceSelected); updatePriceToggleButtons(fixedPriceSelected);
} }
} }

View File

@ -45,6 +45,7 @@ import bisq.core.monetary.Price;
import bisq.core.monetary.Volume; import bisq.core.monetary.Volume;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload; import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService; import bisq.core.provider.price.PriceFeedService;
@ -683,6 +684,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (minAmount.get() != null) if (minAmount.get() != null)
minAmountValidationResult.set(isBtcInputValid(minAmount.get())); minAmountValidationResult.set(isBtcInputValid(minAmount.get()));
} }
// We want to trigger a recalculation of the volume
UserThread.execute(() -> onFocusOutVolumeTextField(true, false));
} }
} }
@ -723,6 +727,13 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
dataModel.calculateAmount(); dataModel.calculateAmount();
applyMakerFee(); applyMakerFee();
} }
// We want to trigger a recalculation of the volume and minAmount
UserThread.execute(() -> {
onFocusOutVolumeTextField(true, false);
// We also need to update minAmount
onFocusOutMinAmountTextField(true, false);
});
} }
} }
@ -743,8 +754,16 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (result.isValid) { if (result.isValid) {
setVolumeToModel(); setVolumeToModel();
ignoreVolumeStringListener = true; ignoreVolumeStringListener = true;
if (dataModel.getVolume().get() != null)
volume.set(btcFormatter.formatVolume(dataModel.getVolume().get())); Volume volume = dataModel.getVolume().get();
if (volume != null) {
// For HalCash we want multiple of 10 EUR
if (dataModel.isHalCashAccount())
volume = OfferUtil.getAdjustedVolumeForHalCash(volume);
this.volume.set(btcFormatter.formatVolume(volume));
}
ignoreVolumeStringListener = false; ignoreVolumeStringListener = false;
dataModel.calculateAmount(); dataModel.calculateAmount();
@ -958,10 +977,16 @@ 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()) {
dataModel.setMinAmount(btcFormatter.parseToCoinWith4Decimals(minAmount.get())); Coin minAmount = btcFormatter.parseToCoinWith4Decimals(this.minAmount.get());
else
if (dataModel.isHalCashAccount() && dataModel.getPrice().get() != null)
minAmount = OfferUtil.getAdjustedMinAmountForHalCash(minAmount, dataModel.getPrice().get());
dataModel.setMinAmount(minAmount);
} else {
dataModel.setMinAmount(null); dataModel.setMinAmount(null);
}
} }
private void setPriceToModel() { private void setPriceToModel() {

View File

@ -35,6 +35,7 @@ import bisq.core.monetary.Price;
import bisq.core.monetary.Volume; import bisq.core.monetary.Volume;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload; import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil;
import bisq.core.payment.AccountAgeWitnessService; import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil; import bisq.core.payment.PaymentAccountUtil;
@ -490,8 +491,11 @@ class TakeOfferDataModel extends OfferDataModel {
if (tradePrice != null && offer != null && if (tradePrice != null && offer != null &&
amount.get() != null && amount.get() != null &&
!amount.get().isZero()) { !amount.get().isZero()) {
volume.set(tradePrice.getVolumeByAmount(amount.get())); Volume volumeByAmount = tradePrice.getVolumeByAmount(amount.get());
//volume.set(new ExchangeRate(tradePrice).coinToFiat(amountAsCoin.get())); if (offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID))
volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount);
volume.set(volumeByAmount);
updateBalance(); updateBalance();
} }

View File

@ -31,6 +31,7 @@ import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload; import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
@ -280,6 +281,11 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
calculateVolume(); calculateVolume();
if (dataModel.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID)) {
dataModel.applyAmount(OfferUtil.getAdjustedMinAmountForHalCash(dataModel.getAmount().get(), dataModel.tradePrice));
amount.set(btcFormatter.formatCoin(dataModel.getAmount().get()));
}
if (!dataModel.isMinAmountLessOrEqualAmount()) if (!dataModel.isMinAmountLessOrEqualAmount())
amountValidationResult.set(new InputValidator.ValidationResult(false, amountValidationResult.set(new InputValidator.ValidationResult(false,
Res.get("takeOffer.validation.amountSmallerThanMinAmount"))); Res.get("takeOffer.validation.amountSmallerThanMinAmount")));

View File

@ -97,7 +97,7 @@ public class EditOfferView extends MutableOfferView<EditOfferViewModel> {
// Workaround to fix margin on top of amount group // Workaround to fix margin on top of amount group
gridPane.setPadding(new Insets(-20, 25, -1, 25)); gridPane.setPadding(new Insets(-20, 25, -1, 25));
updateMarketPriceAvailable(); updatePriceToggle();
updateElementsWithDirection(); updateElementsWithDirection();
model.isNextButtonDisabled.setValue(false); model.isNextButtonDisabled.setValue(false);