round offer amounts within min and max range

This commit is contained in:
woodser 2025-07-12 08:26:17 -04:00 committed by woodser
parent 953157c965
commit 0cf34f3170
15 changed files with 127 additions and 119 deletions

View file

@ -125,15 +125,12 @@ class CoreTradesService {
// adjust amount for fixed-price offer (based on TakeOfferViewModel) // adjust amount for fixed-price offer (based on TakeOfferViewModel)
String currencyCode = offer.getCurrencyCode(); String currencyCode = offer.getCurrencyCode();
OfferDirection direction = offer.getOfferPayload().getDirection(); OfferDirection direction = offer.getOfferPayload().getDirection();
long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction, offer.hasBuyerAsTakerWithoutDeposit()); BigInteger maxAmount = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction, offer.hasBuyerAsTakerWithoutDeposit());
if (offer.getPrice() != null) { if (offer.getPrice() != null) {
if (PaymentMethod.isRoundedForAtmCash(paymentAccount.getPaymentMethod().getId())) { if (PaymentMethod.isRoundedForAtmCash(paymentAccount.getPaymentMethod().getId())) {
amount = CoinUtil.getRoundedAtmCashAmount(amount, offer.getPrice(), maxTradeLimit); amount = CoinUtil.getRoundedAtmCashAmount(amount, offer.getPrice(), offer.getMinAmount(), maxAmount);
} else if (offer.isTraditionalOffer() } else if (offer.isTraditionalOffer() && offer.isRange()) {
&& !amount.equals(offer.getMinAmount()) && !amount.equals(amount)) { amount = CoinUtil.getRoundedAmount(amount, offer.getPrice(), offer.getMinAmount(), maxAmount, offer.getCounterCurrencyCode(), offer.getPaymentMethodId());
// 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
amount = CoinUtil.getRoundedAmount(amount, offer.getPrice(), maxTradeLimit, offer.getCurrencyCode(), offer.getPaymentMethodId());
} }
} }

View file

@ -158,8 +158,8 @@ public class CreateOfferService {
} }
// adjust amount and min amount // adjust amount and min amount
amount = CoinUtil.getRoundedAmount(amount, fixedPrice, null, currencyCode, paymentAccount.getPaymentMethod().getId()); amount = CoinUtil.getRoundedAmount(amount, fixedPrice, minAmount, amount, currencyCode, paymentAccount.getPaymentMethod().getId());
minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, null, currencyCode, paymentAccount.getPaymentMethod().getId()); minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, minAmount, amount, currencyCode, paymentAccount.getPaymentMethod().getId());
// generate one-time challenge for private offer // generate one-time challenge for private offer
String challenge = null; String challenge = null;
@ -184,7 +184,7 @@ public class CreateOfferService {
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount); List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
long maxTradePeriod = paymentAccount.getMaxTradePeriod(); long maxTradePeriod = paymentAccount.getMaxTradePeriod();
boolean hasBuyerAsTakerWithoutDeposit = !isBuyerMaker && isPrivateOffer && buyerAsTakerWithoutDeposit; boolean hasBuyerAsTakerWithoutDeposit = !isBuyerMaker && isPrivateOffer && buyerAsTakerWithoutDeposit;
long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction, hasBuyerAsTakerWithoutDeposit); long maxTradeLimitAsLong = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction, hasBuyerAsTakerWithoutDeposit).longValueExact();
boolean useAutoClose = false; boolean useAutoClose = false;
boolean useReOpenAfterAutoClose = false; boolean useReOpenAfterAutoClose = false;
long lowerClosePrice = 0; long lowerClosePrice = 0;
@ -221,7 +221,7 @@ public class CreateOfferService {
acceptedBanks, acceptedBanks,
Version.VERSION, Version.VERSION,
xmrWalletService.getHeight(), xmrWalletService.getHeight(),
maxTradeLimit, maxTradeLimitAsLong,
maxTradePeriod, maxTradePeriod,
useAutoClose, useAutoClose,
useReOpenAfterAutoClose, useReOpenAfterAutoClose,

View file

@ -40,6 +40,7 @@ import haveno.core.provider.price.MarketPrice;
import haveno.core.provider.price.PriceFeedService; import haveno.core.provider.price.PriceFeedService;
import haveno.core.trade.HavenoUtils; import haveno.core.trade.HavenoUtils;
import haveno.core.util.VolumeUtil; import haveno.core.util.VolumeUtil;
import haveno.core.util.coin.CoinUtil;
import haveno.network.p2p.NodeAddress; import haveno.network.p2p.NodeAddress;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.ReadOnlyStringProperty;
@ -251,12 +252,13 @@ public class Offer implements NetworkPayload, PersistablePayload {
} }
@Nullable @Nullable
public Volume getVolumeByAmount(BigInteger amount) { public Volume getVolumeByAmount(BigInteger amount, BigInteger minAmount, BigInteger maxAmount) {
Price price = getPrice(); Price price = getPrice();
if (price == null || amount == null) { if (price == null || amount == null) {
return null; return null;
} }
Volume volumeByAmount = price.getVolumeByAmount(amount); BigInteger adjustedAmount = CoinUtil.getRoundedAmount(amount, price, minAmount, maxAmount, getCounterCurrencyCode(), getPaymentMethodId());
Volume volumeByAmount = price.getVolumeByAmount(adjustedAmount);
volumeByAmount = VolumeUtil.getAdjustedVolume(volumeByAmount, getPaymentMethod().getId()); volumeByAmount = VolumeUtil.getAdjustedVolume(volumeByAmount, getPaymentMethod().getId());
return volumeByAmount; return volumeByAmount;
@ -385,12 +387,12 @@ public class Offer implements NetworkPayload, PersistablePayload {
@Nullable @Nullable
public Volume getVolume() { public Volume getVolume() {
return getVolumeByAmount(getAmount()); return getVolumeByAmount(getAmount(), getMinAmount(), getAmount());
} }
@Nullable @Nullable
public Volume getMinVolume() { public Volume getMinVolume() {
return getVolumeByAmount(getMinAmount()); return getVolumeByAmount(getMinAmount(), getMinAmount(), getAmount());
} }
public boolean isBuyOffer() { public boolean isBuyOffer() {

View file

@ -120,13 +120,13 @@ public class OfferUtil {
return direction == OfferDirection.BUY; return direction == OfferDirection.BUY;
} }
public long getMaxTradeLimit(PaymentAccount paymentAccount, public BigInteger getMaxTradeLimit(PaymentAccount paymentAccount,
String currencyCode, String currencyCode,
OfferDirection direction, OfferDirection direction,
boolean buyerAsTakerWithoutDeposit) { boolean buyerAsTakerWithoutDeposit) {
return paymentAccount != null return BigInteger.valueOf(paymentAccount != null
? accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, direction, buyerAsTakerWithoutDeposit) ? accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, direction, buyerAsTakerWithoutDeposit)
: 0; : 0);
} }
/** /**

View file

@ -75,19 +75,19 @@ public class CoinUtil {
return BigDecimal.valueOf(percent).multiply(new BigDecimal(amount)).setScale(8, RoundingMode.DOWN).toBigInteger(); return BigDecimal.valueOf(percent).multiply(new BigDecimal(amount)).setScale(8, RoundingMode.DOWN).toBigInteger();
} }
public static BigInteger getRoundedAmount(BigInteger amount, Price price, Long maxTradeLimit, String currencyCode, String paymentMethodId) { public static BigInteger getRoundedAmount(BigInteger amount, Price price, BigInteger minAmount, BigInteger maxAmount, String currencyCode, String paymentMethodId) {
if (price != null) { if (price != null) {
if (PaymentMethod.isRoundedForAtmCash(paymentMethodId)) { if (PaymentMethod.isRoundedForAtmCash(paymentMethodId)) {
return getRoundedAtmCashAmount(amount, price, maxTradeLimit); return getRoundedAtmCashAmount(amount, price, minAmount, maxAmount);
} else if (CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode)) { } else if (CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode)) {
return getRoundedAmountUnit(amount, price, maxTradeLimit); return getRoundedAmountUnit(amount, price, minAmount, maxAmount);
} }
} }
return getRoundedAmount4Decimals(amount, maxTradeLimit); return getRoundedAmount4Decimals(amount);
} }
public static BigInteger getRoundedAtmCashAmount(BigInteger amount, Price price, Long maxTradeLimit) { public static BigInteger getRoundedAtmCashAmount(BigInteger amount, Price price, BigInteger minAmount, BigInteger maxAmount) {
return getAdjustedAmount(amount, price, maxTradeLimit, 10); return getAdjustedAmount(amount, price, minAmount, maxAmount, 10);
} }
/** /**
@ -96,14 +96,15 @@ public class CoinUtil {
* *
* @param amount Monero amount which is a candidate for getting rounded. * @param amount Monero amount which is a candidate for getting rounded.
* @param price Price used in relation to that amount. * @param price Price used in relation to that amount.
* @param maxTradeLimit The max. trade limit of the users account, in atomic units. * @param minAmount The minimum amount.
* @param maxAmount The maximum amount.
* @return The adjusted amount * @return The adjusted amount
*/ */
public static BigInteger getRoundedAmountUnit(BigInteger amount, Price price, Long maxTradeLimit) { public static BigInteger getRoundedAmountUnit(BigInteger amount, Price price, BigInteger minAmount, BigInteger maxAmount) {
return getAdjustedAmount(amount, price, maxTradeLimit, 1); return getAdjustedAmount(amount, price, minAmount, maxAmount, 1);
} }
public static BigInteger getRoundedAmount4Decimals(BigInteger amount, Long maxTradeLimit) { public static BigInteger getRoundedAmount4Decimals(BigInteger amount) {
DecimalFormat decimalFormat = new DecimalFormat("#.####", HavenoUtils.DECIMAL_FORMAT_SYMBOLS); DecimalFormat decimalFormat = new DecimalFormat("#.####", HavenoUtils.DECIMAL_FORMAT_SYMBOLS);
double roundedXmrAmount = Double.parseDouble(decimalFormat.format(HavenoUtils.atomicUnitsToXmr(amount))); double roundedXmrAmount = Double.parseDouble(decimalFormat.format(HavenoUtils.atomicUnitsToXmr(amount)));
return HavenoUtils.xmrToAtomicUnits(roundedXmrAmount); return HavenoUtils.xmrToAtomicUnits(roundedXmrAmount);
@ -115,44 +116,40 @@ public class CoinUtil {
* *
* @param amount amount which is a candidate for getting rounded. * @param amount amount which is a candidate for getting rounded.
* @param price Price used in relation to that amount. * @param price Price used in relation to that amount.
* @param maxTradeLimit The max. trade limit of the users account, in satoshis. * @param minAmount The minimum amount.
* @param maxAmount The maximum amount.
* @param factor The factor used for rounding. E.g. 1 means rounded to units of * @param factor The factor used for rounding. E.g. 1 means rounded to units of
* 1 EUR, 10 means rounded to 10 EUR, etc. * 1 EUR, 10 means rounded to 10 EUR, etc.
* @return The adjusted amount * @return The adjusted amount
*/ */
@VisibleForTesting @VisibleForTesting
static BigInteger getAdjustedAmount(BigInteger amount, Price price, Long maxTradeLimit, int factor) { static BigInteger getAdjustedAmount(BigInteger amount, Price price, BigInteger minAmount, BigInteger maxAmount, int factor) {
checkArgument( checkArgument(
amount.longValueExact() >= Restrictions.getMinTradeAmount().longValueExact(), amount.longValueExact() >= Restrictions.getMinTradeAmount().longValueExact(),
"amount needs to be above minimum of " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr" "amount needs to 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"
); );
checkArgument( checkArgument(
factor > 0, factor > 0,
"factor needs to be positive" "factor needs to 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. // 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.
Volume smallestUnitForVolume = Volume.parse(String.valueOf(factor), price.getCurrencyCode()); Volume smallestUnitForVolume = Volume.parse(String.valueOf(factor), price.getCurrencyCode());
if (smallestUnitForVolume.getValue() <= 0) if (smallestUnitForVolume.getValue() <= 0) return BigInteger.ZERO;
return BigInteger.ZERO;
BigInteger smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume); BigInteger smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume);
long minTradeAmount = Restrictions.getMinTradeAmount().longValueExact(); smallestUnitForAmount = BigInteger.valueOf(Math.max(minAmount.longValueExact(), smallestUnitForAmount.longValueExact()));
checkArgument(
minTradeAmount >= Restrictions.getMinTradeAmount().longValueExact(),
"MinTradeAmount must be at least " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr"
);
smallestUnitForAmount = BigInteger.valueOf(Math.max(minTradeAmount, smallestUnitForAmount.longValueExact()));
// We don't allow smaller amount values than smallestUnitForAmount
boolean useSmallestUnitForAmount = amount.compareTo(smallestUnitForAmount) < 0;
// We get the adjusted volume from our amount // We get the adjusted volume from our amount
boolean useSmallestUnitForAmount = amount.compareTo(smallestUnitForAmount) < 0;
Volume volume = useSmallestUnitForAmount Volume volume = useSmallestUnitForAmount
? getAdjustedVolumeUnit(price.getVolumeByAmount(smallestUnitForAmount), factor) ? getAdjustedVolumeUnit(price.getVolumeByAmount(smallestUnitForAmount), factor)
: getAdjustedVolumeUnit(price.getVolumeByAmount(amount), factor); : getAdjustedVolumeUnit(price.getVolumeByAmount(amount), factor);
if (volume.getValue() <= 0) if (volume.getValue() <= 0) return BigInteger.ZERO;
return BigInteger.ZERO;
// From that adjusted volume we calculate back the amount. It might be a bit different as // From that adjusted volume we calculate back the amount. It might be a bit different as
// the amount used as input before due rounding. // the amount used as input before due rounding.
@ -161,15 +158,23 @@ public class CoinUtil {
// For the amount we allow only 4 decimal places // For the amount we allow only 4 decimal places
long adjustedAmount = HavenoUtils.centinerosToAtomicUnits(Math.round(HavenoUtils.atomicUnitsToCentineros(amountByVolume) / 10000d) * 10000).longValueExact(); long adjustedAmount = HavenoUtils.centinerosToAtomicUnits(Math.round(HavenoUtils.atomicUnitsToCentineros(amountByVolume) / 10000d) * 10000).longValueExact();
// If we are above our trade limit we reduce the amount by the smallestUnitForAmount // If we are below the minAmount we increase the amount by the smallestUnitForAmount
BigInteger smallestUnitForAmountUnadjusted = price.getAmountByVolume(smallestUnitForVolume); BigInteger smallestUnitForAmountUnadjusted = price.getAmountByVolume(smallestUnitForVolume);
if (maxTradeLimit != null) { if (minAmount != null) {
while (adjustedAmount > maxTradeLimit) { while (adjustedAmount < minAmount.longValueExact()) {
adjustedAmount += smallestUnitForAmountUnadjusted.longValueExact();
}
}
// If we are above our trade limit we reduce the amount by the smallestUnitForAmount
if (maxAmount != null) {
while (adjustedAmount > maxAmount.longValueExact()) {
adjustedAmount -= smallestUnitForAmountUnadjusted.longValueExact(); adjustedAmount -= smallestUnitForAmountUnadjusted.longValueExact();
} }
} }
adjustedAmount = Math.max(minTradeAmount, adjustedAmount);
if (maxTradeLimit != null) adjustedAmount = Math.min(maxTradeLimit, adjustedAmount); adjustedAmount = Math.max(minAmount.longValueExact(), adjustedAmount);
if (maxAmount != null) adjustedAmount = Math.min(maxAmount.longValueExact(), adjustedAmount);
return BigInteger.valueOf(adjustedAmount); return BigInteger.valueOf(adjustedAmount);
} }
} }

View file

@ -76,7 +76,8 @@ public class CoinUtilTest {
BigInteger result = CoinUtil.getAdjustedAmount( BigInteger result = CoinUtil.getAdjustedAmount(
HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(), HavenoUtils.xmrToAtomicUnits(0.1),
HavenoUtils.xmrToAtomicUnits(0.2),
1); 1);
assertEquals( assertEquals(
HavenoUtils.formatXmr(Restrictions.MIN_TRADE_AMOUNT, true), HavenoUtils.formatXmr(Restrictions.MIN_TRADE_AMOUNT, true),
@ -88,12 +89,13 @@ public class CoinUtilTest {
CoinUtil.getAdjustedAmount( CoinUtil.getAdjustedAmount(
BigInteger.ZERO, BigInteger.ZERO,
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(), HavenoUtils.xmrToAtomicUnits(0.1),
HavenoUtils.xmrToAtomicUnits(0.2),
1); 1);
fail("Expected IllegalArgumentException to be thrown when amount is too low."); fail("Expected IllegalArgumentException to be thrown when amount is too low.");
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
assertEquals( assertEquals(
"amount needs to be above minimum of 0.1 xmr", "amount needs to be above minimum of 0.1 xmr but was 0.0 xmr",
iae.getMessage(), iae.getMessage(),
"Unexpected exception message." "Unexpected exception message."
); );
@ -102,7 +104,8 @@ public class CoinUtilTest {
result = CoinUtil.getAdjustedAmount( result = CoinUtil.getAdjustedAmount(
HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(), HavenoUtils.xmrToAtomicUnits(0.1),
HavenoUtils.xmrToAtomicUnits(0.2),
1); 1);
assertEquals( assertEquals(
"0.10 XMR", "0.10 XMR",
@ -113,7 +116,8 @@ public class CoinUtilTest {
result = CoinUtil.getAdjustedAmount( result = CoinUtil.getAdjustedAmount(
HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
HavenoUtils.xmrToAtomicUnits(0.25).longValueExact(), HavenoUtils.xmrToAtomicUnits(0.1),
HavenoUtils.xmrToAtomicUnits(0.25),
1); 1);
assertEquals( assertEquals(
"0.10 XMR", "0.10 XMR",
@ -121,18 +125,14 @@ public class CoinUtilTest {
"Minimum trade amount allowed should respect maxTradeLimit and factor, if possible." "Minimum trade amount allowed should respect maxTradeLimit and factor, if possible."
); );
// TODO(chirhonul): The following seems like it should raise an exception or otherwise fail.
// We are asking for the smallest allowed BTC trade when price is 1000 USD each, and the
// max trade limit is 5k sat = 0.00005 BTC. But the returned amount 0.00005 BTC, or
// 0.05 USD worth, which is below the factor of 1 USD, but does respect the maxTradeLimit.
// Basically the given constraints (maxTradeLimit vs factor) are impossible to both fulfill..
result = CoinUtil.getAdjustedAmount( result = CoinUtil.getAdjustedAmount(
HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1),
Price.valueOf("USD", 1000_0000), Price.valueOf("USD", 1000_0000),
HavenoUtils.xmrToAtomicUnits(0.00005).longValueExact(), HavenoUtils.xmrToAtomicUnits(0.1),
HavenoUtils.xmrToAtomicUnits(0.5),
1); 1);
assertEquals( assertEquals(
"0.00005 XMR", "0.10 XMR",
HavenoUtils.formatXmr(result, true), HavenoUtils.formatXmr(result, true),
"Minimum trade amount allowed with low maxTradeLimit should still respect that limit, even if result does not respect the factor specified." "Minimum trade amount allowed with low maxTradeLimit should still respect that limit, even if result does not respect the factor specified."
); );

View file

@ -333,7 +333,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
setSuggestedSecurityDeposit(getPaymentAccount()); setSuggestedSecurityDeposit(getPaymentAccount());
if (amount.get() != null && this.allowAmountUpdate) if (amount.get() != null && this.allowAmountUpdate)
this.amount.set(amount.get().min(BigInteger.valueOf(getMaxTradeLimit()))); this.amount.set(amount.get().min(getMaxTradeLimit()));
} }
} }
@ -472,17 +472,17 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
return marketPriceMarginPct; return marketPriceMarginPct;
} }
long getMaxTradeLimit() { BigInteger getMaxTradeLimit() {
// disallow offers which no buyer can take due to trade limits on release // disallow offers which no buyer can take due to trade limits on release
if (HavenoUtils.isReleasedWithinDays(HavenoUtils.RELEASE_LIMIT_DAYS)) { if (HavenoUtils.isReleasedWithinDays(HavenoUtils.RELEASE_LIMIT_DAYS)) {
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), OfferDirection.BUY, buyerAsTakerWithoutDeposit.get()); return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), OfferDirection.BUY, buyerAsTakerWithoutDeposit.get()));
} }
if (paymentAccount != null) { if (paymentAccount != null) {
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get()); return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get()));
} else { } else {
return 0; return BigInteger.ZERO;
} }
} }
@ -543,9 +543,11 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
// if the volume != amount * price, we need to adjust the amount // if the volume != amount * price, we need to adjust the amount
if (amount.get() == null || !volumeBefore.equals(price.get().getVolumeByAmount(amount.get()))) { if (amount.get() == null || !volumeBefore.equals(price.get().getVolumeByAmount(amount.get()))) {
BigInteger value = price.get().getAmountByVolume(volumeBefore); BigInteger value = price.get().getAmountByVolume(volumeBefore);
value = value.min(BigInteger.valueOf(getMaxTradeLimit())); // adjust if above maximum BigInteger maxAmount = getMaxTradeLimit();
value = value.max(Restrictions.getMinTradeAmount()); // adjust if below minimum BigInteger minAmount = Restrictions.getMinTradeAmount();
value = CoinUtil.getRoundedAmount(value, price.get(), getMaxTradeLimit(), tradeCurrencyCode.get(), paymentAccount.getPaymentMethod().getId()); value = value.min(maxAmount); // adjust if above maximum
value = value.max(minAmount); // adjust if below minimum
value = CoinUtil.getRoundedAmount(value, price.get(), minAmount, maxAmount, tradeCurrencyCode.get(), paymentAccount.getPaymentMethod().getId());
amount.set(value); amount.set(value);
} }

View file

@ -492,7 +492,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
buyerAsTakerWithoutDepositListener = (ov, oldValue, newValue) -> { buyerAsTakerWithoutDepositListener = (ov, oldValue, newValue) -> {
if (dataModel.paymentAccount != null) xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get())); if (dataModel.paymentAccount != null) xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
if (amount.get() != null) amountValidationResult.set(isXmrInputValid(amount.get())); if (amount.get() != null) amountValidationResult.set(isXmrInputValid(amount.get()));
updateSecurityDeposit(); updateSecurityDeposit();
setSecurityDepositToModel(); setSecurityDepositToModel();
@ -610,7 +610,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
} }
if (dataModel.paymentAccount != null) if (dataModel.paymentAccount != null)
xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get())); xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
xmrValidator.setMinValue(Restrictions.getMinTradeAmount()); xmrValidator.setMinValue(Restrictions.getMinTradeAmount());
final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY; final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY;
@ -700,7 +700,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
amountValidationResult.set(isXmrInputValid(amount.get())); amountValidationResult.set(isXmrInputValid(amount.get()));
xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get())); xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
securityDepositValidator.setPaymentAccount(paymentAccount); securityDepositValidator.setPaymentAccount(paymentAccount);
} }
@ -1199,10 +1199,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
if (amount.get() != null && !amount.get().isEmpty()) { if (amount.get() != null && !amount.get().isEmpty()) {
BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter)); BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter));
long maxTradeLimit = dataModel.getMaxTradeLimit(); BigInteger maxTradeLimit = dataModel.getMaxTradeLimit();
Price price = dataModel.getPrice().get(); Price price = dataModel.getPrice().get();
if (price != null && price.isPositive()) { if (price != null && price.isPositive()) {
amount = CoinUtil.getRoundedAmount(amount, price, maxTradeLimit, tradeCurrencyCode.get(), dataModel.getPaymentAccount().getPaymentMethod().getId()); amount = CoinUtil.getRoundedAmount(amount, price, dataModel.getMinAmount().get(), maxTradeLimit, tradeCurrencyCode.get(), dataModel.getPaymentAccount().getPaymentMethod().getId());
} }
dataModel.setAmount(amount); dataModel.setAmount(amount);
if (syncMinAmountWithAmount || if (syncMinAmountWithAmount ||
@ -1221,9 +1221,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
BigInteger minAmount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), xmrFormatter)); BigInteger minAmount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), xmrFormatter));
Price price = dataModel.getPrice().get(); Price price = dataModel.getPrice().get();
long maxTradeLimit = dataModel.getMaxTradeLimit(); BigInteger maxTradeLimit = dataModel.getMaxTradeLimit();
if (price != null && price.isPositive()) { if (price != null && price.isPositive()) {
minAmount = CoinUtil.getRoundedAmount(minAmount, price, maxTradeLimit, tradeCurrencyCode.get(), dataModel.getPaymentAccount().getPaymentMethod().getId()); minAmount = CoinUtil.getRoundedAmount(minAmount, price, dataModel.getMinAmount().get(), maxTradeLimit, tradeCurrencyCode.get(), dataModel.getPaymentAccount().getPaymentMethod().getId());
} }
dataModel.setMinAmount(minAmount); dataModel.setMinAmount(minAmount);

View file

@ -183,7 +183,7 @@ class TakeOfferDataModel extends OfferDataModel {
checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()"); checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()");
paymentAccount = getLastSelectedPaymentAccount(); paymentAccount = getLastSelectedPaymentAccount();
this.amount.set(BigInteger.valueOf(getMaxTradeLimit())); this.amount.set(getMaxTradeLimit());
updateSecurityDeposit(); updateSecurityDeposit();
@ -293,7 +293,7 @@ class TakeOfferDataModel extends OfferDataModel {
if (paymentAccount != null) { if (paymentAccount != null) {
this.paymentAccount = paymentAccount; this.paymentAccount = paymentAccount;
this.amount.set(BigInteger.valueOf(getMaxTradeLimit())); this.amount.set(getMaxTradeLimit());
preferences.setTakeOfferSelectedPaymentAccountId(paymentAccount.getId()); preferences.setTakeOfferSelectedPaymentAccountId(paymentAccount.getId());
} }
@ -338,17 +338,17 @@ class TakeOfferDataModel extends OfferDataModel {
.orElse(firstItem); .orElse(firstItem);
} }
long getMyMaxTradeLimit() { BigInteger getMyMaxTradeLimit() {
if (paymentAccount != null) { if (paymentAccount != null) {
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode(), return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode(),
offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()); offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()));
} else { } else {
return 0; return BigInteger.ZERO;
} }
} }
long getMaxTradeLimit() { BigInteger getMaxTradeLimit() {
return Math.min(offer.getAmount().longValueExact(), getMyMaxTradeLimit()); return offer.getAmount().min(getMyMaxTradeLimit());
} }
boolean canTakeOffer() { boolean canTakeOffer() {
@ -388,7 +388,7 @@ class TakeOfferDataModel extends OfferDataModel {
} }
void maybeApplyAmount(BigInteger amount) { void maybeApplyAmount(BigInteger amount) {
if (amount.compareTo(offer.getMinAmount()) >= 0 && amount.compareTo(BigInteger.valueOf(getMaxTradeLimit())) <= 0) { if (amount.compareTo(offer.getMinAmount()) >= 0 && amount.compareTo(getMaxTradeLimit()) <= 0) {
this.amount.set(amount); this.amount.set(amount);
} }
calculateTotalToPay(); calculateTotalToPay();

View file

@ -208,7 +208,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
errorMessage.set(offer.getErrorMessage()); errorMessage.set(offer.getErrorMessage());
xmrValidator.setMaxValue(offer.getAmount()); xmrValidator.setMaxValue(offer.getAmount());
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
xmrValidator.setMinValue(offer.getMinAmount()); xmrValidator.setMinValue(offer.getMinAmount());
} }
@ -237,7 +237,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
public void onPaymentAccountSelected(PaymentAccount paymentAccount) { public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
dataModel.onPaymentAccountSelected(paymentAccount); dataModel.onPaymentAccountSelected(paymentAccount);
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
updateButtonDisableState(); updateButtonDisableState();
} }
@ -297,12 +297,13 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
calculateVolume(); calculateVolume();
Price tradePrice = dataModel.tradePrice; Price tradePrice = dataModel.tradePrice;
long maxTradeLimit = dataModel.getMaxTradeLimit(); BigInteger minAmount = dataModel.getOffer().getMinAmount();
BigInteger maxAmount = dataModel.getMaxTradeLimit();
if (PaymentMethod.isRoundedForAtmCash(dataModel.getPaymentMethod().getId())) { if (PaymentMethod.isRoundedForAtmCash(dataModel.getPaymentMethod().getId())) {
BigInteger adjustedAmountForAtm = CoinUtil.getRoundedAtmCashAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit); BigInteger adjustedAmountForAtm = CoinUtil.getRoundedAtmCashAmount(dataModel.getAmount().get(), tradePrice, minAmount, maxAmount);
dataModel.maybeApplyAmount(adjustedAmountForAtm); dataModel.maybeApplyAmount(adjustedAmountForAtm);
} else if (dataModel.getOffer().isTraditionalOffer()) { } else if (dataModel.getOffer().isTraditionalOffer() && dataModel.getOffer().isRange()) {
BigInteger roundedAmount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId()); BigInteger roundedAmount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), tradePrice, minAmount, maxAmount, dataModel.getOffer().getCounterCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
dataModel.maybeApplyAmount(roundedAmount); dataModel.maybeApplyAmount(roundedAmount);
} }
amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get())); amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get()));
@ -568,13 +569,14 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
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(), xmrFormatter)); BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter));
long maxTradeLimit = dataModel.getMaxTradeLimit(); BigInteger minAmount = dataModel.getOffer().getMinAmount();
BigInteger maxAmount = dataModel.getMaxTradeLimit();
Price price = dataModel.tradePrice; Price price = dataModel.tradePrice;
if (price != null) { if (price != null) {
if (dataModel.isRoundedForAtmCash()) { if (dataModel.isRoundedForAtmCash()) {
amount = CoinUtil.getRoundedAtmCashAmount(amount, price, maxTradeLimit); amount = CoinUtil.getRoundedAtmCashAmount(amount, price, minAmount, maxAmount);
} else if (dataModel.getOffer().isTraditionalOffer()) { } else if (dataModel.getOffer().isTraditionalOffer() && dataModel.getOffer().isRange()) {
amount = CoinUtil.getRoundedAmount(amount, price, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId()); amount = CoinUtil.getRoundedAmount(amount, price, minAmount, maxAmount, dataModel.getOffer().getCounterCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
} }
} }
dataModel.maybeApplyAmount(amount); dataModel.maybeApplyAmount(amount);

View file

@ -239,7 +239,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
HavenoUtils.formatXmr(tradeAmount, true)); HavenoUtils.formatXmr(tradeAmount, true));
addSeparator(gridPane, ++rowIndex); addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo,
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount))); VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount, offer.getMinAmount(), tradeAmount)));
} else { } else {
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
HavenoUtils.formatXmr(offer.getAmount(), true)); HavenoUtils.formatXmr(offer.getAmount(), true));

View file

@ -88,7 +88,7 @@ public class OfferBookChartViewModelTest {
final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null); final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null);
model.activate(); model.activate();
assertEquals(7, model.maxPlacesForBuyPrice.intValue()); assertEquals(9, model.maxPlacesForBuyPrice.intValue());
offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.price, 940164750000L)))); offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.price, 940164750000L))));
assertEquals(9, model.maxPlacesForBuyPrice.intValue()); // 9401.6475 assertEquals(9, model.maxPlacesForBuyPrice.intValue()); // 9401.6475
offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.price, 1010164750000L)))); offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.price, 1010164750000L))));
@ -117,11 +117,11 @@ public class OfferBookChartViewModelTest {
final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null); final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null);
model.activate(); model.activate();
assertEquals(1, model.maxPlacesForBuyVolume.intValue()); //0 assertEquals(3, model.maxPlacesForBuyVolume.intValue()); //0
offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.amount, 1000000000000L)))); offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.amount, 1000000000000L))));
assertEquals(2, model.maxPlacesForBuyVolume.intValue()); //10 assertEquals(4, model.maxPlacesForBuyVolume.intValue()); //10
offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.amount, 221286000000000L)))); offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.amount, 221286000000000L))));
assertEquals(4, model.maxPlacesForBuyVolume.intValue()); //2213 assertEquals(6, model.maxPlacesForBuyVolume.intValue()); //2213
} }
@Test @Test
@ -166,7 +166,7 @@ public class OfferBookChartViewModelTest {
final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null); final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null);
model.activate(); model.activate();
assertEquals(7, model.maxPlacesForSellPrice.intValue()); // 10.0000 default price assertEquals(9, model.maxPlacesForSellPrice.intValue()); // 10.0000 default price
offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.price, 940164750000L)))); offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.price, 940164750000L))));
assertEquals(9, model.maxPlacesForSellPrice.intValue()); // 9401.6475 assertEquals(9, model.maxPlacesForSellPrice.intValue()); // 9401.6475
offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.price, 1010164750000L)))); offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.price, 1010164750000L))));
@ -195,10 +195,10 @@ public class OfferBookChartViewModelTest {
final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null); final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null);
model.activate(); model.activate();
assertEquals(1, model.maxPlacesForSellVolume.intValue()); //0 assertEquals(3, model.maxPlacesForSellVolume.intValue()); //0
offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.amount, 1000000000000L)))); offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.amount, 1000000000000L))));
assertEquals(2, model.maxPlacesForSellVolume.intValue()); //10 assertEquals(4, model.maxPlacesForSellVolume.intValue()); //10
offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.amount, 221286000000000L)))); offerBookListItems.addAll(make(xmrSellItem.but(with(OfferBookListItemMaker.amount, 221286000000000L))));
assertEquals(4, model.maxPlacesForSellVolume.intValue()); //2213 assertEquals(6, model.maxPlacesForSellVolume.intValue()); //2213
} }
} }

View file

@ -42,9 +42,9 @@ public class OfferBookListItemMaker {
public static final Instantiator<OfferBookListItem> OfferBookListItem = lookup -> public static final Instantiator<OfferBookListItem> OfferBookListItem = lookup ->
new OfferBookListItem(make(xmrUsdOffer.but( new OfferBookListItem(make(xmrUsdOffer.but(
with(OfferMaker.price, lookup.valueOf(price, 1000000000L)), with(OfferMaker.price, lookup.valueOf(price, 100000000000L)),
with(OfferMaker.amount, lookup.valueOf(amount, 1000000000L)), with(OfferMaker.amount, lookup.valueOf(amount, 100000000000L)),
with(OfferMaker.minAmount, lookup.valueOf(amount, 1000000000L)), with(OfferMaker.minAmount, lookup.valueOf(amount, 100000000000L)),
with(OfferMaker.direction, lookup.valueOf(direction, OfferDirection.BUY)), with(OfferMaker.direction, lookup.valueOf(direction, OfferDirection.BUY)),
with(OfferMaker.useMarketBasedPrice, lookup.valueOf(useMarketBasedPrice, false)), with(OfferMaker.useMarketBasedPrice, lookup.valueOf(useMarketBasedPrice, false)),
with(OfferMaker.marketPriceMargin, lookup.valueOf(marketPriceMargin, 0.0)), with(OfferMaker.marketPriceMargin, lookup.valueOf(marketPriceMargin, 0.0)),
@ -56,8 +56,8 @@ public class OfferBookListItemMaker {
public static final Instantiator<OfferBookListItem> OfferBookListItemWithRange = lookup -> public static final Instantiator<OfferBookListItem> OfferBookListItemWithRange = lookup ->
new OfferBookListItem(make(xmrUsdOffer.but( new OfferBookListItem(make(xmrUsdOffer.but(
MakeItEasy.with(OfferMaker.price, lookup.valueOf(price, 100000L)), MakeItEasy.with(OfferMaker.price, lookup.valueOf(price, 100000L)),
with(OfferMaker.minAmount, lookup.valueOf(minAmount, 1000000000L)), with(OfferMaker.minAmount, lookup.valueOf(minAmount, 100000000000L)),
with(OfferMaker.amount, lookup.valueOf(amount, 2000000000L))))); with(OfferMaker.amount, lookup.valueOf(amount, 200000000000L)))));
public static final Maker<OfferBookListItem> xmrBuyItem = a(OfferBookListItem); public static final Maker<OfferBookListItem> xmrBuyItem = a(OfferBookListItem);
public static final Maker<OfferBookListItem> xmrSellItem = a(OfferBookListItem, with(direction, OfferDirection.SELL)); public static final Maker<OfferBookListItem> xmrSellItem = a(OfferBookListItem, with(direction, OfferDirection.SELL));

View file

@ -310,9 +310,9 @@ public class OfferBookViewModelTest {
null, null, null, getPriceUtil(), null, coinFormatter, null); null, null, null, getPriceUtil(), null, coinFormatter, null);
model.activate(); model.activate();
assertEquals(5, model.maxPlacesForVolume.intValue());
offerBookListItems.addAll(make(xmrBuyItem.but(with(amount, 20000000000000L))));
assertEquals(7, model.maxPlacesForVolume.intValue()); assertEquals(7, model.maxPlacesForVolume.intValue());
offerBookListItems.addAll(make(xmrBuyItem.but(with(amount, 20000000000000L))));
assertEquals(9, model.maxPlacesForVolume.intValue());
} }
@Test @Test
@ -360,7 +360,7 @@ public class OfferBookViewModelTest {
null, null, null, getPriceUtil(), null, coinFormatter, null); null, null, null, getPriceUtil(), null, coinFormatter, null);
model.activate(); model.activate();
assertEquals(7, model.maxPlacesForPrice.intValue()); assertEquals(9, model.maxPlacesForPrice.intValue());
offerBookListItems.addAll(make(xmrBuyItem.but(with(price, 1495582400000L)))); //149558240 offerBookListItems.addAll(make(xmrBuyItem.but(with(price, 1495582400000L)))); //149558240
assertEquals(10, model.maxPlacesForPrice.intValue()); assertEquals(10, model.maxPlacesForPrice.intValue());
offerBookListItems.addAll(make(xmrBuyItem.but(with(price, 149558240000L)))); //149558240 offerBookListItems.addAll(make(xmrBuyItem.but(with(price, 149558240000L)))); //149558240
@ -453,7 +453,7 @@ public class OfferBookViewModelTest {
assertEquals("12557.2046", model.getPrice(lowItem)); assertEquals("12557.2046", model.getPrice(lowItem));
assertEquals("(1.00%)", model.getPriceAsPercentage(lowItem)); assertEquals("(1.00%)", model.getPriceAsPercentage(lowItem));
assertEquals("10.0000", model.getPrice(fixedItem)); assertEquals("1000.0000", model.getPrice(fixedItem));
offerBookListItems.addAll(item); offerBookListItems.addAll(item);
assertEquals("14206.1304", model.getPrice(item)); assertEquals("14206.1304", model.getPrice(item));
assertEquals("(-12.00%)", model.getPriceAsPercentage(item)); assertEquals("(-12.00%)", model.getPriceAsPercentage(item));

View file

@ -80,8 +80,8 @@ public class OfferMaker {
lookup.valueOf(price, 100000L), lookup.valueOf(price, 100000L),
lookup.valueOf(marketPriceMargin, 0.0), lookup.valueOf(marketPriceMargin, 0.0),
lookup.valueOf(useMarketBasedPrice, false), lookup.valueOf(useMarketBasedPrice, false),
lookup.valueOf(amount, 100000L), lookup.valueOf(amount, 100000000000L),
lookup.valueOf(minAmount, 100000L), lookup.valueOf(minAmount, 100000000000L),
lookup.valueOf(makerFeePct, .0015), lookup.valueOf(makerFeePct, .0015),
lookup.valueOf(takerFeePct, .0075), lookup.valueOf(takerFeePct, .0075),
lookup.valueOf(penaltyFeePct, 0.03), lookup.valueOf(penaltyFeePct, 0.03),
@ -97,7 +97,7 @@ public class OfferMaker {
}}), }}),
null, null,
null, null,
"2", "3",
lookup.valueOf(blockHeight, 700000L), lookup.valueOf(blockHeight, 700000L),
lookup.valueOf(tradeLimit, 0L), lookup.valueOf(tradeLimit, 0L),
lookup.valueOf(maxTradePeriod, 0L), lookup.valueOf(maxTradePeriod, 0L),