mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-09-20 13:04:40 -04:00
round offer amounts within min and max range
This commit is contained in:
parent
953157c965
commit
0cf34f3170
15 changed files with 127 additions and 119 deletions
|
@ -125,15 +125,12 @@ class CoreTradesService {
|
|||
// adjust amount for fixed-price offer (based on TakeOfferViewModel)
|
||||
String currencyCode = offer.getCurrencyCode();
|
||||
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 (PaymentMethod.isRoundedForAtmCash(paymentAccount.getPaymentMethod().getId())) {
|
||||
amount = CoinUtil.getRoundedAtmCashAmount(amount, offer.getPrice(), maxTradeLimit);
|
||||
} else if (offer.isTraditionalOffer()
|
||||
&& !amount.equals(offer.getMinAmount()) && !amount.equals(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
|
||||
amount = CoinUtil.getRoundedAmount(amount, offer.getPrice(), maxTradeLimit, offer.getCurrencyCode(), offer.getPaymentMethodId());
|
||||
amount = CoinUtil.getRoundedAtmCashAmount(amount, offer.getPrice(), offer.getMinAmount(), maxAmount);
|
||||
} else if (offer.isTraditionalOffer() && offer.isRange()) {
|
||||
amount = CoinUtil.getRoundedAmount(amount, offer.getPrice(), offer.getMinAmount(), maxAmount, offer.getCounterCurrencyCode(), offer.getPaymentMethodId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -158,8 +158,8 @@ public class CreateOfferService {
|
|||
}
|
||||
|
||||
// adjust amount and min amount
|
||||
amount = CoinUtil.getRoundedAmount(amount, fixedPrice, null, currencyCode, paymentAccount.getPaymentMethod().getId());
|
||||
minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, null, currencyCode, paymentAccount.getPaymentMethod().getId());
|
||||
amount = CoinUtil.getRoundedAmount(amount, fixedPrice, minAmount, amount, currencyCode, paymentAccount.getPaymentMethod().getId());
|
||||
minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, minAmount, amount, currencyCode, paymentAccount.getPaymentMethod().getId());
|
||||
|
||||
// generate one-time challenge for private offer
|
||||
String challenge = null;
|
||||
|
@ -184,7 +184,7 @@ public class CreateOfferService {
|
|||
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
|
||||
long maxTradePeriod = paymentAccount.getMaxTradePeriod();
|
||||
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 useReOpenAfterAutoClose = false;
|
||||
long lowerClosePrice = 0;
|
||||
|
@ -221,7 +221,7 @@ public class CreateOfferService {
|
|||
acceptedBanks,
|
||||
Version.VERSION,
|
||||
xmrWalletService.getHeight(),
|
||||
maxTradeLimit,
|
||||
maxTradeLimitAsLong,
|
||||
maxTradePeriod,
|
||||
useAutoClose,
|
||||
useReOpenAfterAutoClose,
|
||||
|
|
|
@ -40,6 +40,7 @@ import haveno.core.provider.price.MarketPrice;
|
|||
import haveno.core.provider.price.PriceFeedService;
|
||||
import haveno.core.trade.HavenoUtils;
|
||||
import haveno.core.util.VolumeUtil;
|
||||
import haveno.core.util.coin.CoinUtil;
|
||||
import haveno.network.p2p.NodeAddress;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyStringProperty;
|
||||
|
@ -251,12 +252,13 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public Volume getVolumeByAmount(BigInteger amount) {
|
||||
public Volume getVolumeByAmount(BigInteger amount, BigInteger minAmount, BigInteger maxAmount) {
|
||||
Price price = getPrice();
|
||||
if (price == null || amount == 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());
|
||||
|
||||
return volumeByAmount;
|
||||
|
@ -385,12 +387,12 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
|||
|
||||
@Nullable
|
||||
public Volume getVolume() {
|
||||
return getVolumeByAmount(getAmount());
|
||||
return getVolumeByAmount(getAmount(), getMinAmount(), getAmount());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Volume getMinVolume() {
|
||||
return getVolumeByAmount(getMinAmount());
|
||||
return getVolumeByAmount(getMinAmount(), getMinAmount(), getAmount());
|
||||
}
|
||||
|
||||
public boolean isBuyOffer() {
|
||||
|
|
|
@ -120,13 +120,13 @@ public class OfferUtil {
|
|||
return direction == OfferDirection.BUY;
|
||||
}
|
||||
|
||||
public long getMaxTradeLimit(PaymentAccount paymentAccount,
|
||||
public BigInteger getMaxTradeLimit(PaymentAccount paymentAccount,
|
||||
String currencyCode,
|
||||
OfferDirection direction,
|
||||
boolean buyerAsTakerWithoutDeposit) {
|
||||
return paymentAccount != null
|
||||
return BigInteger.valueOf(paymentAccount != null
|
||||
? accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, direction, buyerAsTakerWithoutDeposit)
|
||||
: 0;
|
||||
: 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,19 +75,19 @@ public class CoinUtil {
|
|||
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 (PaymentMethod.isRoundedForAtmCash(paymentMethodId)) {
|
||||
return getRoundedAtmCashAmount(amount, price, maxTradeLimit);
|
||||
return getRoundedAtmCashAmount(amount, price, minAmount, maxAmount);
|
||||
} 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) {
|
||||
return getAdjustedAmount(amount, price, maxTradeLimit, 10);
|
||||
public static BigInteger getRoundedAtmCashAmount(BigInteger amount, Price price, BigInteger minAmount, BigInteger maxAmount) {
|
||||
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 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
|
||||
*/
|
||||
public static BigInteger getRoundedAmountUnit(BigInteger amount, Price price, Long maxTradeLimit) {
|
||||
return getAdjustedAmount(amount, price, maxTradeLimit, 1);
|
||||
public static BigInteger getRoundedAmountUnit(BigInteger amount, Price price, BigInteger minAmount, BigInteger maxAmount) {
|
||||
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);
|
||||
double roundedXmrAmount = Double.parseDouble(decimalFormat.format(HavenoUtils.atomicUnitsToXmr(amount)));
|
||||
return HavenoUtils.xmrToAtomicUnits(roundedXmrAmount);
|
||||
|
@ -115,44 +116,40 @@ public class CoinUtil {
|
|||
*
|
||||
* @param amount amount which is a candidate for getting rounded.
|
||||
* @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
|
||||
* 1 EUR, 10 means rounded to 10 EUR, etc.
|
||||
* @return The adjusted amount
|
||||
*/
|
||||
@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(
|
||||
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(
|
||||
factor > 0,
|
||||
"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());
|
||||
if (smallestUnitForVolume.getValue() <= 0)
|
||||
return BigInteger.ZERO;
|
||||
|
||||
if (smallestUnitForVolume.getValue() <= 0) return BigInteger.ZERO;
|
||||
BigInteger smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume);
|
||||
long minTradeAmount = Restrictions.getMinTradeAmount().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;
|
||||
smallestUnitForAmount = BigInteger.valueOf(Math.max(minAmount.longValueExact(), smallestUnitForAmount.longValueExact()));
|
||||
|
||||
// We get the adjusted volume from our amount
|
||||
boolean useSmallestUnitForAmount = amount.compareTo(smallestUnitForAmount) < 0;
|
||||
Volume volume = useSmallestUnitForAmount
|
||||
? getAdjustedVolumeUnit(price.getVolumeByAmount(smallestUnitForAmount), factor)
|
||||
: getAdjustedVolumeUnit(price.getVolumeByAmount(amount), factor);
|
||||
if (volume.getValue() <= 0)
|
||||
return BigInteger.ZERO;
|
||||
if (volume.getValue() <= 0) return BigInteger.ZERO;
|
||||
|
||||
// From that adjusted volume we calculate back the amount. It might be a bit different as
|
||||
// the amount used as input before due rounding.
|
||||
|
@ -161,15 +158,23 @@ public class CoinUtil {
|
|||
// For the amount we allow only 4 decimal places
|
||||
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);
|
||||
if (maxTradeLimit != null) {
|
||||
while (adjustedAmount > maxTradeLimit) {
|
||||
if (minAmount != null) {
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ public class CoinUtilTest {
|
|||
BigInteger result = CoinUtil.getAdjustedAmount(
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
HavenoUtils.xmrToAtomicUnits(0.2),
|
||||
1);
|
||||
assertEquals(
|
||||
HavenoUtils.formatXmr(Restrictions.MIN_TRADE_AMOUNT, true),
|
||||
|
@ -88,12 +89,13 @@ public class CoinUtilTest {
|
|||
CoinUtil.getAdjustedAmount(
|
||||
BigInteger.ZERO,
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
HavenoUtils.xmrToAtomicUnits(0.2),
|
||||
1);
|
||||
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",
|
||||
"amount needs to be above minimum of 0.1 xmr but was 0.0 xmr",
|
||||
iae.getMessage(),
|
||||
"Unexpected exception message."
|
||||
);
|
||||
|
@ -102,7 +104,8 @@ public class CoinUtilTest {
|
|||
result = CoinUtil.getAdjustedAmount(
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(),
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
HavenoUtils.xmrToAtomicUnits(0.2),
|
||||
1);
|
||||
assertEquals(
|
||||
"0.10 XMR",
|
||||
|
@ -113,7 +116,8 @@ public class CoinUtilTest {
|
|||
result = CoinUtil.getAdjustedAmount(
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.25).longValueExact(),
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
HavenoUtils.xmrToAtomicUnits(0.25),
|
||||
1);
|
||||
assertEquals(
|
||||
"0.10 XMR",
|
||||
|
@ -121,18 +125,14 @@ public class CoinUtilTest {
|
|||
"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(
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
Price.valueOf("USD", 1000_0000),
|
||||
HavenoUtils.xmrToAtomicUnits(0.00005).longValueExact(),
|
||||
HavenoUtils.xmrToAtomicUnits(0.1),
|
||||
HavenoUtils.xmrToAtomicUnits(0.5),
|
||||
1);
|
||||
assertEquals(
|
||||
"0.00005 XMR",
|
||||
"0.10 XMR",
|
||||
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."
|
||||
);
|
||||
|
|
|
@ -333,7 +333,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
|
|||
setSuggestedSecurityDeposit(getPaymentAccount());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
long getMaxTradeLimit() {
|
||||
BigInteger getMaxTradeLimit() {
|
||||
|
||||
// disallow offers which no buyer can take due to trade limits on release
|
||||
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) {
|
||||
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get());
|
||||
return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get()));
|
||||
} 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 (amount.get() == null || !volumeBefore.equals(price.get().getVolumeByAmount(amount.get()))) {
|
||||
BigInteger value = price.get().getAmountByVolume(volumeBefore);
|
||||
value = value.min(BigInteger.valueOf(getMaxTradeLimit())); // adjust if above maximum
|
||||
value = value.max(Restrictions.getMinTradeAmount()); // adjust if below minimum
|
||||
value = CoinUtil.getRoundedAmount(value, price.get(), getMaxTradeLimit(), tradeCurrencyCode.get(), paymentAccount.getPaymentMethod().getId());
|
||||
BigInteger maxAmount = getMaxTradeLimit();
|
||||
BigInteger minAmount = Restrictions.getMinTradeAmount();
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -492,7 +492,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
|||
|
||||
buyerAsTakerWithoutDepositListener = (ov, oldValue, newValue) -> {
|
||||
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()));
|
||||
updateSecurityDeposit();
|
||||
setSecurityDepositToModel();
|
||||
|
@ -610,7 +610,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
|||
}
|
||||
if (dataModel.paymentAccount != null)
|
||||
xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
|
||||
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
|
||||
xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
|
||||
xmrValidator.setMinValue(Restrictions.getMinTradeAmount());
|
||||
|
||||
final boolean isBuy = dataModel.getDirection() == OfferDirection.BUY;
|
||||
|
@ -700,7 +700,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
|||
amountValidationResult.set(isXmrInputValid(amount.get()));
|
||||
|
||||
xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get()));
|
||||
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
|
||||
xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
|
||||
|
||||
securityDepositValidator.setPaymentAccount(paymentAccount);
|
||||
}
|
||||
|
@ -1199,10 +1199,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
|||
if (amount.get() != null && !amount.get().isEmpty()) {
|
||||
BigInteger amount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.amount.get(), xmrFormatter));
|
||||
|
||||
long maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
BigInteger maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
Price price = dataModel.getPrice().get();
|
||||
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);
|
||||
if (syncMinAmountWithAmount ||
|
||||
|
@ -1221,9 +1221,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
|||
BigInteger minAmount = HavenoUtils.coinToAtomicUnits(DisplayUtils.parseToCoinWith4Decimals(this.minAmount.get(), xmrFormatter));
|
||||
|
||||
Price price = dataModel.getPrice().get();
|
||||
long maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
BigInteger maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
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);
|
||||
|
|
|
@ -183,7 +183,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||
checkArgument(!possiblePaymentAccounts.isEmpty(), "possiblePaymentAccounts.isEmpty()");
|
||||
paymentAccount = getLastSelectedPaymentAccount();
|
||||
|
||||
this.amount.set(BigInteger.valueOf(getMaxTradeLimit()));
|
||||
this.amount.set(getMaxTradeLimit());
|
||||
|
||||
updateSecurityDeposit();
|
||||
|
||||
|
@ -293,7 +293,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||
if (paymentAccount != null) {
|
||||
this.paymentAccount = paymentAccount;
|
||||
|
||||
this.amount.set(BigInteger.valueOf(getMaxTradeLimit()));
|
||||
this.amount.set(getMaxTradeLimit());
|
||||
|
||||
preferences.setTakeOfferSelectedPaymentAccountId(paymentAccount.getId());
|
||||
}
|
||||
|
@ -338,17 +338,17 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||
.orElse(firstItem);
|
||||
}
|
||||
|
||||
long getMyMaxTradeLimit() {
|
||||
BigInteger getMyMaxTradeLimit() {
|
||||
if (paymentAccount != null) {
|
||||
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode(),
|
||||
offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit());
|
||||
return BigInteger.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode(),
|
||||
offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()));
|
||||
} else {
|
||||
return 0;
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
long getMaxTradeLimit() {
|
||||
return Math.min(offer.getAmount().longValueExact(), getMyMaxTradeLimit());
|
||||
BigInteger getMaxTradeLimit() {
|
||||
return offer.getAmount().min(getMyMaxTradeLimit());
|
||||
}
|
||||
|
||||
boolean canTakeOffer() {
|
||||
|
@ -388,7 +388,7 @@ class TakeOfferDataModel extends OfferDataModel {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
calculateTotalToPay();
|
||||
|
|
|
@ -208,7 +208,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||
errorMessage.set(offer.getErrorMessage());
|
||||
|
||||
xmrValidator.setMaxValue(offer.getAmount());
|
||||
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
|
||||
xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
|
||||
xmrValidator.setMinValue(offer.getMinAmount());
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||
|
||||
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
|
||||
dataModel.onPaymentAccountSelected(paymentAccount);
|
||||
xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit()));
|
||||
xmrValidator.setMaxTradeLimit(dataModel.getMaxTradeLimit());
|
||||
updateButtonDisableState();
|
||||
}
|
||||
|
||||
|
@ -297,12 +297,13 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||
calculateVolume();
|
||||
|
||||
Price tradePrice = dataModel.tradePrice;
|
||||
long maxTradeLimit = dataModel.getMaxTradeLimit();
|
||||
BigInteger minAmount = dataModel.getOffer().getMinAmount();
|
||||
BigInteger maxAmount = dataModel.getMaxTradeLimit();
|
||||
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);
|
||||
} else if (dataModel.getOffer().isTraditionalOffer()) {
|
||||
BigInteger roundedAmount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
|
||||
} else if (dataModel.getOffer().isTraditionalOffer() && dataModel.getOffer().isRange()) {
|
||||
BigInteger roundedAmount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), tradePrice, minAmount, maxAmount, dataModel.getOffer().getCounterCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
|
||||
dataModel.maybeApplyAmount(roundedAmount);
|
||||
}
|
||||
amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get()));
|
||||
|
@ -568,13 +569,14 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||
private void setAmountToModel() {
|
||||
if (amount.get() != null && !amount.get().isEmpty()) {
|
||||
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;
|
||||
if (price != null) {
|
||||
if (dataModel.isRoundedForAtmCash()) {
|
||||
amount = CoinUtil.getRoundedAtmCashAmount(amount, price, maxTradeLimit);
|
||||
} else if (dataModel.getOffer().isTraditionalOffer()) {
|
||||
amount = CoinUtil.getRoundedAmount(amount, price, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
|
||||
amount = CoinUtil.getRoundedAtmCashAmount(amount, price, minAmount, maxAmount);
|
||||
} else if (dataModel.getOffer().isTraditionalOffer() && dataModel.getOffer().isRange()) {
|
||||
amount = CoinUtil.getRoundedAmount(amount, price, minAmount, maxAmount, dataModel.getOffer().getCounterCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
|
||||
}
|
||||
}
|
||||
dataModel.maybeApplyAmount(amount);
|
||||
|
|
|
@ -239,7 +239,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||
HavenoUtils.formatXmr(tradeAmount, true));
|
||||
addSeparator(gridPane, ++rowIndex);
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo,
|
||||
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
|
||||
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount, offer.getMinAmount(), tradeAmount)));
|
||||
} else {
|
||||
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
|
||||
HavenoUtils.formatXmr(offer.getAmount(), true));
|
||||
|
|
|
@ -88,7 +88,7 @@ public class OfferBookChartViewModelTest {
|
|||
|
||||
final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null);
|
||||
model.activate();
|
||||
assertEquals(7, model.maxPlacesForBuyPrice.intValue());
|
||||
assertEquals(9, model.maxPlacesForBuyPrice.intValue());
|
||||
offerBookListItems.addAll(make(xmrBuyItem.but(with(OfferBookListItemMaker.price, 940164750000L))));
|
||||
assertEquals(9, model.maxPlacesForBuyPrice.intValue()); // 9401.6475
|
||||
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);
|
||||
model.activate();
|
||||
assertEquals(1, model.maxPlacesForBuyVolume.intValue()); //0
|
||||
assertEquals(3, model.maxPlacesForBuyVolume.intValue()); //0
|
||||
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))));
|
||||
assertEquals(4, model.maxPlacesForBuyVolume.intValue()); //2213
|
||||
assertEquals(6, model.maxPlacesForBuyVolume.intValue()); //2213
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -166,7 +166,7 @@ public class OfferBookChartViewModelTest {
|
|||
|
||||
final OfferBookChartViewModel model = new OfferBookChartViewModel(offerBook, null, empty, service, null, null);
|
||||
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))));
|
||||
assertEquals(9, model.maxPlacesForSellPrice.intValue()); // 9401.6475
|
||||
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);
|
||||
model.activate();
|
||||
assertEquals(1, model.maxPlacesForSellVolume.intValue()); //0
|
||||
assertEquals(3, model.maxPlacesForSellVolume.intValue()); //0
|
||||
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))));
|
||||
assertEquals(4, model.maxPlacesForSellVolume.intValue()); //2213
|
||||
assertEquals(6, model.maxPlacesForSellVolume.intValue()); //2213
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@ public class OfferBookListItemMaker {
|
|||
|
||||
public static final Instantiator<OfferBookListItem> OfferBookListItem = lookup ->
|
||||
new OfferBookListItem(make(xmrUsdOffer.but(
|
||||
with(OfferMaker.price, lookup.valueOf(price, 1000000000L)),
|
||||
with(OfferMaker.amount, lookup.valueOf(amount, 1000000000L)),
|
||||
with(OfferMaker.minAmount, lookup.valueOf(amount, 1000000000L)),
|
||||
with(OfferMaker.price, lookup.valueOf(price, 100000000000L)),
|
||||
with(OfferMaker.amount, lookup.valueOf(amount, 100000000000L)),
|
||||
with(OfferMaker.minAmount, lookup.valueOf(amount, 100000000000L)),
|
||||
with(OfferMaker.direction, lookup.valueOf(direction, OfferDirection.BUY)),
|
||||
with(OfferMaker.useMarketBasedPrice, lookup.valueOf(useMarketBasedPrice, false)),
|
||||
with(OfferMaker.marketPriceMargin, lookup.valueOf(marketPriceMargin, 0.0)),
|
||||
|
@ -56,8 +56,8 @@ public class OfferBookListItemMaker {
|
|||
public static final Instantiator<OfferBookListItem> OfferBookListItemWithRange = lookup ->
|
||||
new OfferBookListItem(make(xmrUsdOffer.but(
|
||||
MakeItEasy.with(OfferMaker.price, lookup.valueOf(price, 100000L)),
|
||||
with(OfferMaker.minAmount, lookup.valueOf(minAmount, 1000000000L)),
|
||||
with(OfferMaker.amount, lookup.valueOf(amount, 2000000000L)))));
|
||||
with(OfferMaker.minAmount, lookup.valueOf(minAmount, 100000000000L)),
|
||||
with(OfferMaker.amount, lookup.valueOf(amount, 200000000000L)))));
|
||||
|
||||
public static final Maker<OfferBookListItem> xmrBuyItem = a(OfferBookListItem);
|
||||
public static final Maker<OfferBookListItem> xmrSellItem = a(OfferBookListItem, with(direction, OfferDirection.SELL));
|
||||
|
|
|
@ -310,9 +310,9 @@ public class OfferBookViewModelTest {
|
|||
null, null, null, getPriceUtil(), null, coinFormatter, null);
|
||||
model.activate();
|
||||
|
||||
assertEquals(5, model.maxPlacesForVolume.intValue());
|
||||
offerBookListItems.addAll(make(xmrBuyItem.but(with(amount, 20000000000000L))));
|
||||
assertEquals(7, model.maxPlacesForVolume.intValue());
|
||||
offerBookListItems.addAll(make(xmrBuyItem.but(with(amount, 20000000000000L))));
|
||||
assertEquals(9, model.maxPlacesForVolume.intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -360,7 +360,7 @@ public class OfferBookViewModelTest {
|
|||
null, null, null, getPriceUtil(), null, coinFormatter, null);
|
||||
model.activate();
|
||||
|
||||
assertEquals(7, model.maxPlacesForPrice.intValue());
|
||||
assertEquals(9, model.maxPlacesForPrice.intValue());
|
||||
offerBookListItems.addAll(make(xmrBuyItem.but(with(price, 1495582400000L)))); //149558240
|
||||
assertEquals(10, model.maxPlacesForPrice.intValue());
|
||||
offerBookListItems.addAll(make(xmrBuyItem.but(with(price, 149558240000L)))); //149558240
|
||||
|
@ -453,7 +453,7 @@ public class OfferBookViewModelTest {
|
|||
|
||||
assertEquals("12557.2046", model.getPrice(lowItem));
|
||||
assertEquals("(1.00%)", model.getPriceAsPercentage(lowItem));
|
||||
assertEquals("10.0000", model.getPrice(fixedItem));
|
||||
assertEquals("1000.0000", model.getPrice(fixedItem));
|
||||
offerBookListItems.addAll(item);
|
||||
assertEquals("14206.1304", model.getPrice(item));
|
||||
assertEquals("(-12.00%)", model.getPriceAsPercentage(item));
|
||||
|
|
|
@ -80,8 +80,8 @@ public class OfferMaker {
|
|||
lookup.valueOf(price, 100000L),
|
||||
lookup.valueOf(marketPriceMargin, 0.0),
|
||||
lookup.valueOf(useMarketBasedPrice, false),
|
||||
lookup.valueOf(amount, 100000L),
|
||||
lookup.valueOf(minAmount, 100000L),
|
||||
lookup.valueOf(amount, 100000000000L),
|
||||
lookup.valueOf(minAmount, 100000000000L),
|
||||
lookup.valueOf(makerFeePct, .0015),
|
||||
lookup.valueOf(takerFeePct, .0075),
|
||||
lookup.valueOf(penaltyFeePct, 0.03),
|
||||
|
@ -97,7 +97,7 @@ public class OfferMaker {
|
|||
}}),
|
||||
null,
|
||||
null,
|
||||
"2",
|
||||
"3",
|
||||
lookup.valueOf(blockHeight, 700000L),
|
||||
lookup.valueOf(tradeLimit, 0L),
|
||||
lookup.valueOf(maxTradePeriod, 0L),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue