fix amount adjustment when creating new offer (#1868)

This commit is contained in:
woodser 2025-07-19 08:00:46 -04:00 committed by GitHub
parent 83e1e56efb
commit 071659aec1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 49 additions and 24 deletions

View file

@ -35,6 +35,7 @@ import haveno.core.trade.HavenoUtils;
import haveno.core.trade.statistics.TradeStatisticsManager;
import haveno.core.user.User;
import haveno.core.util.coin.CoinUtil;
import haveno.core.xmr.wallet.Restrictions;
import haveno.core.xmr.wallet.XmrWalletService;
import haveno.network.p2p.NodeAddress;
import haveno.network.p2p.P2PService;
@ -92,7 +93,6 @@ public class CreateOfferService {
Version.VERSION.replace(".", "");
}
// TODO: add trigger price?
public Offer createAndGetOffer(String offerId,
OfferDirection direction,
String currencyCode,
@ -158,8 +158,9 @@ public class CreateOfferService {
}
// adjust amount and min amount
amount = CoinUtil.getRoundedAmount(amount, fixedPrice, minAmount, amount, currencyCode, paymentAccount.getPaymentMethod().getId());
minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, minAmount, amount, currencyCode, paymentAccount.getPaymentMethod().getId());
BigInteger maxTradeLimit = offerUtil.getMaxTradeLimitForRelease(paymentAccount, currencyCode, direction, buyerAsTakerWithoutDeposit);
amount = CoinUtil.getRoundedAmount(amount, fixedPrice, Restrictions.getMinTradeAmount(), maxTradeLimit, currencyCode, paymentAccount.getPaymentMethod().getId());
minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, Restrictions.getMinTradeAmount(), maxTradeLimit, currencyCode, paymentAccount.getPaymentMethod().getId());
// generate one-time challenge for private offer
String challenge = null;
@ -241,7 +242,6 @@ public class CreateOfferService {
return offer;
}
// TODO: add trigger price?
public Offer createClonedOffer(Offer sourceOffer,
String currencyCode,
Price fixedPrice,

View file

@ -56,6 +56,7 @@ import haveno.core.payment.PayPalAccount;
import haveno.core.payment.PaymentAccount;
import haveno.core.provider.price.MarketPrice;
import haveno.core.provider.price.PriceFeedService;
import haveno.core.trade.HavenoUtils;
import haveno.core.trade.statistics.ReferralIdService;
import haveno.core.user.AutoConfirmSettings;
import haveno.core.user.Preferences;
@ -269,4 +270,21 @@ public class OfferUtil {
public static boolean isCryptoOffer(Offer offer) {
return offer.getCounterCurrencyCode().equals("XMR");
}
public BigInteger getMaxTradeLimitForRelease(PaymentAccount paymentAccount,
String currencyCode,
OfferDirection direction,
boolean buyerAsTakerWithoutDeposit) {
// disallow offers which no buyer can take due to trade limits on release
if (HavenoUtils.isReleasedWithinDays(HavenoUtils.RELEASE_LIMIT_DAYS)) {
return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, OfferDirection.BUY, buyerAsTakerWithoutDeposit));
}
if (paymentAccount != null) {
return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, direction, buyerAsTakerWithoutDeposit));
} else {
return BigInteger.ZERO;
}
}
}

View file

@ -148,11 +148,17 @@ public class HavenoUtils {
@SuppressWarnings("unused")
public static Date getReleaseDate() {
if (RELEASE_DATE == null) return null;
try {
return DATE_FORMAT.parse(RELEASE_DATE);
} catch (Exception e) {
log.error("Failed to parse release date: " + RELEASE_DATE, e);
throw new IllegalArgumentException(e);
return parseDate(RELEASE_DATE);
}
private static Date parseDate(String date) {
synchronized (DATE_FORMAT) {
try {
return DATE_FORMAT.parse(date);
} catch (Exception e) {
log.error("Failed to parse date: " + date, e);
throw new IllegalArgumentException(e);
}
}
}

View file

@ -126,16 +126,27 @@ public class CoinUtil {
static BigInteger getAdjustedAmount(BigInteger amount, Price price, BigInteger minAmount, BigInteger maxAmount, int factor) {
checkArgument(
amount.longValueExact() >= Restrictions.getMinTradeAmount().longValueExact(),
"amount needs to be above minimum of " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr but was " + HavenoUtils.atomicUnitsToXmr(amount) + " xmr"
"amount must be above minimum of " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr but was " + HavenoUtils.atomicUnitsToXmr(amount) + " xmr"
);
if (minAmount == null) minAmount = Restrictions.getMinTradeAmount();
checkArgument(
minAmount.longValueExact() >= Restrictions.getMinTradeAmount().longValueExact(),
"minAmount needs to be above minimum of " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr but was " + HavenoUtils.atomicUnitsToXmr(minAmount) + " xmr"
"minAmount must be above minimum of " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr but was " + HavenoUtils.atomicUnitsToXmr(minAmount) + " xmr"
);
if (maxAmount != null) {
checkArgument(
amount.longValueExact() <= maxAmount.longValueExact(),
"amount must be below maximum of " + HavenoUtils.atomicUnitsToXmr(maxAmount) + " xmr but was " + HavenoUtils.atomicUnitsToXmr(amount) + " xmr"
);
checkArgument(
maxAmount.longValueExact() >= minAmount.longValueExact(),
"maxAmount must be above minimum of " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr but was " + HavenoUtils.atomicUnitsToXmr(maxAmount) + " xmr"
);
}
checkArgument(
factor > 0,
"factor needs to be positive"
"factor must be positive"
);
// Amount must result in a volume of min factor units of the fiat currency, e.g. 1 EUR or 10 EUR in case of HalCash.

View file

@ -95,7 +95,7 @@ public class CoinUtilTest {
fail("Expected IllegalArgumentException to be thrown when amount is too low.");
} catch (IllegalArgumentException iae) {
assertEquals(
"amount needs to be above minimum of 0.1 xmr but was 0.0 xmr",
"amount must be above minimum of 0.1 xmr but was 0.0 xmr",
iae.getMessage(),
"Unexpected exception message."
);

View file

@ -473,17 +473,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
}
BigInteger getMaxTradeLimit() {
// disallow offers which no buyer can take due to trade limits on release
if (HavenoUtils.isReleasedWithinDays(HavenoUtils.RELEASE_LIMIT_DAYS)) {
return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), OfferDirection.BUY, buyerAsTakerWithoutDeposit.get()));
}
if (paymentAccount != null) {
return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get()));
} else {
return BigInteger.ZERO;
}
return offerUtil.getMaxTradeLimitForRelease(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get());
}
BigInteger getMinTradeLimit() {