From c40499969282722a5ecf0f2a159293b632260701 Mon Sep 17 00:00:00 2001 From: woodser Date: Wed, 29 Jan 2025 09:24:20 -0500 Subject: [PATCH] enable floating price offers for cardless cash --- .../core/payment/payload/PaymentMethod.java | 3 +- .../resources/i18n/displayStrings.properties | 4 ++- .../offer/takeoffer/TakeOfferDataModel.java | 17 +++++---- .../offer/takeoffer/TakeOfferViewModel.java | 36 +++++-------------- 4 files changed, 24 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java b/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java index 49302f610a0..e8f27c9d7f6 100644 --- a/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java @@ -597,7 +597,6 @@ public static boolean isRoundedForAtmCash(String id) { } public static boolean isFixedPriceOnly(String id) { - return id.equals(PaymentMethod.CASH_AT_ATM_ID) || - id.equals(PaymentMethod.HAL_CASH_ID); + return id.equals(PaymentMethod.HAL_CASH_ID); } } diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 05ecbdebfd3..5cc6a41b62a 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -3014,9 +3014,11 @@ payment.tradingRestrictions=Please review the maker's terms and conditions.\n\ If you do not meet the requirements do not take this trade. payment.cashAtAtm.info=Cardless Cash: Cardless withdraw at ATM using code\n\n\ To use this payment method:\n\n\ - 1. Create a Cardless Cash payment account, lising your accepted banks, regions, or other terms to be shown with the offer.\n\n\ + 1. Create a Cardless Cash payment account, listing your accepted banks, regions, or other terms to be shown with the offer.\n\n\ 2. Create or take an offer with the payment account.\n\n\ 3. When the offer is taken, chat with your peer to coordinate a time to complete the payment and share the payment details.\n\n\ + If the trade amount is above the cash withdrawal limit, traders should split it into multiple transactions.\n\n\ + ATM cash trades must be in multiples of 10. Using range offers is recommended so the XMR amount can adjust to match the exact price.\n\n\ If you cannot complete the transaction as specified in your trade contract, you may lose some (or all) of your security deposit. payment.cashAtAtm.extraInfo.prompt=Please state on your offers: \n\n\ Your accepted banks / locations; \n\ diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java index 0f6c5db8fb6..f6b947954d7 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -183,7 +183,7 @@ void initWithData(Offer offer) { checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()"); paymentAccount = getLastSelectedPaymentAccount(); - this.amount.set(offer.getAmount().min(BigInteger.valueOf(getMaxTradeLimit()))); + this.amount.set(BigInteger.valueOf(getMaxTradeLimit())); updateSecurityDeposit(); @@ -292,8 +292,7 @@ public void onPaymentAccountSelected(PaymentAccount paymentAccount) { if (paymentAccount != null) { this.paymentAccount = paymentAccount; - long myLimit = getMaxTradeLimit(); - this.amount.set(offer.getMinAmount().max(amount.get().min(BigInteger.valueOf(myLimit)))); + this.amount.set(BigInteger.valueOf(getMaxTradeLimit())); preferences.setTakeOfferSelectedPaymentAccountId(paymentAccount.getId()); } @@ -338,7 +337,7 @@ public PaymentAccount getLastSelectedPaymentAccount() { .orElse(firstItem); } - long getMaxTradeLimit() { + long getMyMaxTradeLimit() { if (paymentAccount != null) { return accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()); @@ -347,6 +346,10 @@ long getMaxTradeLimit() { } } + long getMaxTradeLimit() { + return Math.min(offer.getAmount().longValueExact(), getMyMaxTradeLimit()); + } + boolean canTakeOffer() { return GUIUtil.canCreateOrTakeOfferOrShowPopup(user, navigation) && GUIUtil.isBootstrappedOrShowPopup(p2PService); @@ -383,8 +386,10 @@ void calculateVolume() { } } - void applyAmount(BigInteger amount) { - this.amount.set(amount.min(BigInteger.valueOf(getMaxTradeLimit()))); + void maybeApplyAmount(BigInteger amount) { + if (amount.compareTo(offer.getMinAmount()) >= 0 && amount.compareTo(BigInteger.valueOf(getMaxTradeLimit())) <= 0) { + this.amount.set(amount); + } calculateTotalToPay(); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java index c8f21ff0aab..c73ce988c6c 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -208,7 +208,7 @@ void initWithData(Offer offer) { errorMessage.set(offer.getErrorMessage()); xmrValidator.setMaxValue(offer.getAmount()); - xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()).min(offer.getAmount())); + xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMinValue(offer.getMinAmount()); } @@ -237,7 +237,7 @@ void onTakeOffer(Runnable resultHandler) { public void onPaymentAccountSelected(PaymentAccount paymentAccount) { dataModel.onPaymentAccountSelected(paymentAccount); - xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()).min(offer.getAmount())); + xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); updateButtonDisableState(); } @@ -299,20 +299,13 @@ void onFocusOutAmountTextField(boolean oldValue, boolean newValue, String userIn Price tradePrice = dataModel.tradePrice; long maxTradeLimit = dataModel.getMaxTradeLimit(); if (PaymentMethod.isRoundedForAtmCash(dataModel.getPaymentMethod().getId())) { - BigInteger adjustedAmountForAtm = CoinUtil.getRoundedAtmCashAmount(dataModel.getAmount().get(), - tradePrice, - maxTradeLimit); - dataModel.applyAmount(adjustedAmountForAtm); - amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get())); + BigInteger adjustedAmountForAtm = CoinUtil.getRoundedAtmCashAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit); + dataModel.maybeApplyAmount(adjustedAmountForAtm); } else if (dataModel.getOffer().isTraditionalOffer()) { - if (!isAmountEqualMinAmount(dataModel.getAmount().get()) && (!isAmountEqualMaxAmount(dataModel.getAmount().get()))) { - // We only apply the rounding if the amount is variable (minAmount is lower as amount). - // Otherwise we could get an amount lower then the minAmount set by rounding - BigInteger roundedAmount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId()); - dataModel.applyAmount(roundedAmount); - } - amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get())); + BigInteger roundedAmount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId()); + dataModel.maybeApplyAmount(roundedAmount); } + amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get())); if (!dataModel.isMinAmountLessOrEqualAmount()) amountValidationResult.set(new InputValidator.ValidationResult(false, @@ -580,25 +573,14 @@ private void setAmountToModel() { if (price != null) { if (dataModel.isRoundedForAtmCash()) { amount = CoinUtil.getRoundedAtmCashAmount(amount, price, maxTradeLimit); - } else if (dataModel.getOffer().isTraditionalOffer() - && !isAmountEqualMinAmount(amount) && !isAmountEqualMaxAmount(amount)) { - // We only apply the rounding if the amount is variable (minAmount is lower as amount). - // Otherwise we could get an amount lower then the minAmount set by rounding + } else if (dataModel.getOffer().isTraditionalOffer()) { amount = CoinUtil.getRoundedAmount(amount, price, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId()); } } - dataModel.applyAmount(amount); + dataModel.maybeApplyAmount(amount); } } - private boolean isAmountEqualMinAmount(BigInteger amount) { - return offer.getMinAmount().equals(amount); - } - - private boolean isAmountEqualMaxAmount(BigInteger amount) { - return offer.getAmount().equals(amount); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Getters ///////////////////////////////////////////////////////////////////////////////////////////