mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-09-23 22:44:59 -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)
|
// 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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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."
|
||||||
);
|
);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue