support goldback (XGB)

This commit is contained in:
woodser 2023-09-03 10:45:55 -04:00
parent 6a49fffb38
commit 9c2308f7a3
23 changed files with 135 additions and 121 deletions

View file

@ -209,7 +209,7 @@ public class AbstractPaymentAccountTest extends MethodTest {
protected final String getCommaDelimitedTraditionalCurrencyCodes(Collection<TraditionalCurrency> traditionalCurrencies) {
return traditionalCurrencies.stream()
.sorted(Comparator.comparing(TradeCurrency::getCode))
.map(c -> c.getCurrency().getCurrencyCode())
.map(c -> c.getCode())
.collect(Collectors.joining(","));
}

View file

@ -56,6 +56,14 @@ public class CurrencyUtil {
private static String baseCurrencyCode = "XMR";
private static List<TraditionalCurrency> getTraditionalNonFiatCurrencies() {
return Arrays.asList(
new TraditionalCurrency("XAG", "Gold"),
new TraditionalCurrency("XAU", "Silver"),
new TraditionalCurrency("XGB", "Goldback")
);
}
// Calls to isTraditionalCurrency and isCryptoCurrency are very frequent so we use a cache of the results.
// The main improvement was already achieved with using memoize for the source maps, but
// the caching still reduces performance costs by about 20% for isCryptoCurrency (1752 ms vs 2121 ms) and about 50%
@ -101,7 +109,7 @@ public class CurrencyUtil {
public static Collection<TraditionalCurrency> getAllSortedTraditionalCurrencies(Comparator comparator) {
return (List<TraditionalCurrency>) getAllSortedTraditionalCurrencies().stream()
.sorted(comparator) // sorted by comparator param
.sorted(comparator)
.collect(Collectors.toList());
}
@ -109,7 +117,7 @@ public class CurrencyUtil {
List<TraditionalCurrency> currencies = CountryUtil.getAllCountries().stream()
.map(country -> getCurrencyByCountryCode(country.code))
.collect(Collectors.toList());
for (String isoCode : nonFiatIsoCodes) currencies.add(new TraditionalCurrency(Currency.getInstance(isoCode)));
currencies.addAll(getTraditionalNonFiatCurrencies());
return currencies.stream().sorted(TradeCurrency::compareTo)
.distinct()
.collect(Collectors.toMap(TradeCurrency::getCode, Function.identity(), (x, y) -> x, LinkedHashMap::new));
@ -131,12 +139,14 @@ public class CurrencyUtil {
public static List<TraditionalCurrency> getMainTraditionalCurrencies() {
List<TraditionalCurrency> list = getMainFiatCurrencies();
for (String isoCode : nonFiatIsoCodes) list.add(new TraditionalCurrency(isoCode));
list.addAll(getTraditionalNonFiatCurrencies());
postProcessTraditionalCurrenciesList(list);
return list;
}
private static List<String> nonFiatIsoCodes = Arrays.asList("XAG", "XAU");
private static boolean isTraditionalNonFiatCurrency(String currencyCode) {
return getTraditionalNonFiatCurrencies().stream().anyMatch(c -> c.getCode().equals(currencyCode));
}
private static void postProcessTraditionalCurrenciesList(List<TraditionalCurrency> list) {
list.sort(TradeCurrency::compareTo);
@ -209,7 +219,7 @@ public class CurrencyUtil {
public static boolean isFiatCurrency(String currencyCode) {
if (!isTraditionalCurrency(currencyCode)) return false;
if ("XAG".equalsIgnoreCase(currencyCode) || "XAU".equalsIgnoreCase(currencyCode)) return false;
if (isTraditionalNonFiatCurrency(currencyCode)) return false;
return true;
}
@ -224,7 +234,7 @@ public class CurrencyUtil {
boolean isTraditionalCurrency = currencyCode != null
&& !currencyCode.isEmpty()
&& !isCryptoCurrency(currencyCode)
&& Currency.getInstance(currencyCode) != null;
&& (isTraditionalNonFiatCurrency(currencyCode) || Currency.getInstance(currencyCode) != null);
if (currencyCode != null) {
isTraditionalCurrencyMap.put(currencyCode, isTraditionalCurrency);
@ -237,6 +247,17 @@ public class CurrencyUtil {
}
}
public static boolean isVolumeRoundedToNearestUnit(String currencyCode) {
return isFiatCurrency(currencyCode) ||
"XGB".equals(currencyCode.toUpperCase());
}
public static boolean isPricePrecise(String currencyCode) {
return isCryptoCurrency(currencyCode) ||
"XAU".equals(currencyCode.toUpperCase()) ||
"XAG".equals(currencyCode.toUpperCase());
}
public static Optional<TraditionalCurrency> getTraditionalCurrency(String currencyCode) {
return Optional.ofNullable(traditionalCurrencyMapSupplier.get().get(currencyCode));
}

View file

@ -30,15 +30,22 @@ import java.util.Locale;
@ToString
@Getter
public final class TraditionalCurrency extends TradeCurrency {
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
private final static String PREFIX = "";
private final Currency currency;
public TraditionalCurrency(String currencyCode) {
this(Currency.getInstance(currencyCode), getLocale());
}
public TraditionalCurrency(String currencyCode, String name) {
super(currencyCode, name);
}
public TraditionalCurrency(TraditionalCurrency currency) {
this(currency.getCode(), currency.getName());
}
@SuppressWarnings("WeakerAccess")
public TraditionalCurrency(Currency currency) {
this(currency, getLocale());
@ -47,7 +54,6 @@ public final class TraditionalCurrency extends TradeCurrency {
@SuppressWarnings("WeakerAccess")
public TraditionalCurrency(Currency currency, Locale locale) {
super(currency.getCurrencyCode(), currency.getDisplayName(locale));
this.currency = currency;
}
@ -57,15 +63,15 @@ public final class TraditionalCurrency extends TradeCurrency {
@Override
public Message toProtoMessage() {
protobuf.Currency.Builder currencyBuilder = protobuf.Currency.newBuilder().setCurrencyCode(currency.getCurrencyCode());
protobuf.TraditionalCurrency.Builder traditionalCurrencyBuilder = protobuf.TraditionalCurrency.newBuilder().setCurrency(currencyBuilder);
return getTradeCurrencyBuilder()
.setTraditionalCurrency(traditionalCurrencyBuilder)
.setCode(code)
.setName(name)
.setTraditionalCurrency(protobuf.TraditionalCurrency.newBuilder())
.build();
}
public static TraditionalCurrency fromProto(protobuf.TradeCurrency proto) {
return new TraditionalCurrency(proto.getCode());
return new TraditionalCurrency(proto.getCode(), proto.getName());
}

View file

@ -632,7 +632,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
public void setTraditionalCurrencies(List<TraditionalCurrency> currencies) {
traditionalCurrenciesAsObservable.setAll(currencies.stream()
.map(traditionalCurrency -> new TraditionalCurrency(traditionalCurrency.getCurrency()))
.map(traditionalCurrency -> new TraditionalCurrency(traditionalCurrency))
.distinct().collect(Collectors.toList()));
requestPersistence();
}

View file

@ -29,9 +29,8 @@ public class FormattingUtils {
public final static String RANGE_SEPARATOR = " - ";
private static final MonetaryFormat fiatPriceFormat = new MonetaryFormat().shift(0).minDecimals(4).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat nonFiatPriceFormat = new MonetaryFormat().shift(0).minDecimals(8).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat traditionalFormat = new MonetaryFormat().shift(0).minDecimals(TraditionalMoney.SMALLEST_UNIT_EXPONENT).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat priceFormat4Decimals = new MonetaryFormat().shift(0).minDecimals(4).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat priceFormat8Decimals = new MonetaryFormat().shift(0).minDecimals(8).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat cryptoFormat = new MonetaryFormat().shift(0).minDecimals(CryptoMoney.SMALLEST_UNIT_EXPONENT).repeatOptionalDecimals(0, 0);
private static final DecimalFormat decimalFormat = new DecimalFormat("#.#");
@ -293,11 +292,7 @@ public class FormattingUtils {
return formattedNumber;
}
public static MonetaryFormat getMonetaryFormat(String currencyCode) {
return CurrencyUtil.isTraditionalCurrency(currencyCode) ? traditionalFormat : cryptoFormat;
}
public static MonetaryFormat getPriceMonetaryFormat(String currencyCode) {
return CurrencyUtil.isFiatCurrency(currencyCode) ? fiatPriceFormat : nonFiatPriceFormat;
return CurrencyUtil.isPricePrecise(currencyCode) ? priceFormat8Decimals : priceFormat4Decimals;
}
}

View file

@ -29,8 +29,8 @@ import haveno.core.provider.price.MarketPrice;
import haveno.core.provider.price.PriceFeedService;
import haveno.core.trade.statistics.TradeStatisticsManager;
import haveno.core.user.Preferences;
import haveno.core.util.validation.NonFiatPriceValidator;
import haveno.core.util.validation.FiatPriceValidator;
import haveno.core.util.validation.AmountValidator8Decimals;
import haveno.core.util.validation.AmountValidator4Decimals;
import haveno.core.util.validation.InputValidator;
import haveno.core.util.validation.MonetaryValidator;
import lombok.extern.slf4j.Slf4j;
@ -53,21 +53,21 @@ public class PriceUtil {
this.priceFeedService = priceFeedService;
}
public static MonetaryValidator getPriceValidator(boolean isFiatCurrency) {
return isFiatCurrency ?
new FiatPriceValidator() :
new NonFiatPriceValidator();
public static MonetaryValidator getPriceValidator(String currencyCode) {
return CurrencyUtil.isPricePrecise(currencyCode) ?
new AmountValidator4Decimals() :
new AmountValidator8Decimals();
}
public static InputValidator.ValidationResult isTriggerPriceValid(String triggerPriceAsString,
MarketPrice marketPrice,
boolean isSellOffer,
boolean isFiatCurrency) {
String currencyCode) {
if (triggerPriceAsString == null || triggerPriceAsString.isEmpty()) {
return new InputValidator.ValidationResult(true);
}
InputValidator.ValidationResult result = getPriceValidator(isFiatCurrency).validate(triggerPriceAsString);
InputValidator.ValidationResult result = getPriceValidator(currencyCode).validate(triggerPriceAsString);
if (!result.isValid) {
return result;
}
@ -76,7 +76,8 @@ public class PriceUtil {
long marketPriceAsLong = PriceUtil.getMarketPriceAsLong("" + marketPrice.getPrice(), marketPrice.getCurrencyCode());
String marketPriceAsString = FormattingUtils.formatMarketPrice(marketPrice.getPrice(), marketPrice.getCurrencyCode());
if ((isSellOffer && isFiatCurrency) || (!isSellOffer && !isFiatCurrency)) {
boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode);
if ((isSellOffer && !isCryptoCurrency) || (!isSellOffer && isCryptoCurrency)) {
if (triggerPriceAsLong >= marketPriceAsLong) {
return new InputValidator.ValidationResult(false,
Res.get("createOffer.triggerPrice.invalid.tooHigh", marketPriceAsString));

View file

@ -38,33 +38,33 @@ import java.util.Locale;
public class VolumeUtil {
private static final MonetaryFormat FIAT_VOLUME_FORMAT = new MonetaryFormat().shift(0).minDecimals(0).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat TRADITIONAL_VOLUME_FORMAT = new MonetaryFormat().shift(0).minDecimals(4).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat VOLUME_FORMAT_UNIT = new MonetaryFormat().shift(0).minDecimals(0).repeatOptionalDecimals(0, 0);
private static final MonetaryFormat VOLUME_FORMAT_PRECISE = new MonetaryFormat().shift(0).minDecimals(4).repeatOptionalDecimals(0, 0);
private static double EXPONENT = Math.pow(10, TraditionalMoney.SMALLEST_UNIT_EXPONENT); // 1000000000000 with precision 8
public static Volume getAdjustedVolume(Volume volumeByAmount, String paymentMethodId) {
if (PaymentMethod.isRoundedForAtmCash(paymentMethodId))
return VolumeUtil.getRoundedAtmCashVolume(volumeByAmount);
else if (CurrencyUtil.isFiatCurrency(volumeByAmount.getCurrencyCode()))
return VolumeUtil.getRoundedFiatVolume(volumeByAmount);
else if (CurrencyUtil.isVolumeRoundedToNearestUnit(volumeByAmount.getCurrencyCode()))
return VolumeUtil.getRoundedVolumeUnit(volumeByAmount);
else if (CurrencyUtil.isTraditionalCurrency(volumeByAmount.getCurrencyCode()))
return VolumeUtil.getRoundedTraditionalVolume(volumeByAmount);
return VolumeUtil.getRoundedVolumePrecise(volumeByAmount);
return volumeByAmount;
}
public static Volume getRoundedFiatVolume(Volume volumeByAmount) {
// We want to get rounded to 1 unit of the fiat currency, e.g. 1 EUR.
return getAdjustedFiatVolume(volumeByAmount, 1);
public static Volume getRoundedVolumeUnit(Volume volumeByAmount) {
// We want to get rounded to 1 unit of the currency, e.g. 1 EUR.
return getAdjustedVolumeUnit(volumeByAmount, 1);
}
private static Volume getRoundedAtmCashVolume(Volume volumeByAmount) {
// EUR has precision TraditionalMoney.SMALLEST_UNIT_EXPONENT and we want multiple of 10 so we divide by EXPONENT then
// round and multiply with 10
return getAdjustedFiatVolume(volumeByAmount, 10);
return getAdjustedVolumeUnit(volumeByAmount, 10);
}
public static Volume getRoundedTraditionalVolume(Volume volumeByAmount) {
public static Volume getRoundedVolumePrecise(Volume volumeByAmount) {
DecimalFormat decimalFormat = new DecimalFormat("#.####");
double roundedVolume = Double.parseDouble(decimalFormat.format(Double.parseDouble(volumeByAmount.toString())));
return Volume.parse(String.valueOf(roundedVolume), volumeByAmount.getCurrencyCode());
@ -77,7 +77,7 @@ public class VolumeUtil {
* units of 1 EUR, 10 means rounded to 10 EUR.
* @return The adjusted Fiat volume
*/
public static Volume getAdjustedFiatVolume(Volume volumeByAmount, int factor) {
public static Volume getAdjustedVolumeUnit(Volume volumeByAmount, int factor) {
// Fiat currencies use precision TraditionalMoney.SMALLEST_UNIT_EXPONENT and we want multiple of factor so we divide
// by EXPONENT * factor then round and multiply with factor
long roundedVolume = Math.round((double) volumeByAmount.getValue() / (EXPONENT * factor)) * factor;
@ -168,6 +168,6 @@ public class VolumeUtil {
}
private static MonetaryFormat getMonetaryFormat(String currencyCode) {
return CurrencyUtil.isFiatCurrency(currencyCode) ? FIAT_VOLUME_FORMAT : TRADITIONAL_VOLUME_FORMAT;
return CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode) ? VOLUME_FORMAT_UNIT : VOLUME_FORMAT_PRECISE;
}
}

View file

@ -32,7 +32,7 @@ import java.math.BigInteger;
import java.text.DecimalFormat;
import static com.google.common.base.Preconditions.checkArgument;
import static haveno.core.util.VolumeUtil.getAdjustedFiatVolume;
import static haveno.core.util.VolumeUtil.getAdjustedVolumeUnit;
public class CoinUtil {
@ -82,10 +82,10 @@ public class CoinUtil {
public static BigInteger getRoundedAmount(BigInteger amount, Price price, long maxTradeLimit, String currencyCode, String paymentMethodId) {
if (PaymentMethod.isRoundedForAtmCash(paymentMethodId)) {
return getRoundedAtmCashAmount(amount, price, maxTradeLimit);
} else if (CurrencyUtil.isFiatCurrency(currencyCode)) {
return getRoundedFiatAmount(amount, price, maxTradeLimit);
} else if (CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode)) {
return getRoundedAmountUnit(amount, price, maxTradeLimit);
} else if (CurrencyUtil.isTraditionalCurrency(currencyCode)) {
return getRoundedTraditionalAmount(amount, price, maxTradeLimit);
return getRoundedAmountPrecise(amount, price, maxTradeLimit);
}
return amount;
}
@ -98,16 +98,16 @@ public class CoinUtil {
* Calculate the possibly adjusted amount for {@code amount}, taking into account the
* {@code price} and {@code maxTradeLimit} and {@code factor}.
*
* @param amount Bitcoin 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 maxTradeLimit The max. trade limit of the users account, in satoshis.
* @param maxTradeLimit The max. trade limit of the users account, in atomic units.
* @return The adjusted amount
*/
public static BigInteger getRoundedFiatAmount(BigInteger amount, Price price, long maxTradeLimit) {
public static BigInteger getRoundedAmountUnit(BigInteger amount, Price price, long maxTradeLimit) {
return getAdjustedAmount(amount, price, maxTradeLimit, 1);
}
public static BigInteger getRoundedTraditionalAmount(BigInteger amount, Price price, long maxTradeLimit) {
public static BigInteger getRoundedAmountPrecise(BigInteger amount, Price price, long maxTradeLimit) {
DecimalFormat decimalFormat = new DecimalFormat("#.####");
double roundedXmrAmount = Double.parseDouble(decimalFormat.format(HavenoUtils.atomicUnitsToXmr(amount)));
return HavenoUtils.xmrToAtomicUnits(roundedXmrAmount);
@ -154,8 +154,8 @@ public class CoinUtil {
// We get the adjusted volume from our amount
Volume volume = useSmallestUnitForAmount
? getAdjustedFiatVolume(price.getVolumeByAmount(smallestUnitForAmount), factor)
: getAdjustedFiatVolume(price.getVolumeByAmount(amount), factor);
? getAdjustedVolumeUnit(price.getVolumeByAmount(smallestUnitForAmount), factor)
: getAdjustedVolumeUnit(price.getVolumeByAmount(amount), factor);
if (volume.getValue() <= 0)
return BigInteger.valueOf(0);

View file

@ -19,7 +19,7 @@ package haveno.core.util.validation;
import javax.inject.Inject;
public class FiatPriceValidator extends MonetaryValidator {
public class AmountValidator4Decimals extends MonetaryValidator {
@Override
public double getMinValue() {
return 0.0001;
@ -33,6 +33,6 @@ public class FiatPriceValidator extends MonetaryValidator {
}
@Inject
public FiatPriceValidator() {
public AmountValidator4Decimals() {
}
}

View file

@ -19,7 +19,7 @@ package haveno.core.util.validation;
import javax.inject.Inject;
public class NonFiatPriceValidator extends MonetaryValidator {
public class AmountValidator8Decimals extends MonetaryValidator {
@Override
public double getMinValue() {
return 0.00000001;
@ -32,6 +32,6 @@ public class NonFiatPriceValidator extends MonetaryValidator {
}
@Inject
public NonFiatPriceValidator() {
public AmountValidator8Decimals() {
}
}

View file

@ -40,8 +40,6 @@ import haveno.core.user.User;
import haveno.core.util.FormattingUtils;
import haveno.core.util.ParsingUtils;
import haveno.core.util.PriceUtil;
import haveno.core.util.validation.NonFiatPriceValidator;
import haveno.core.util.validation.FiatPriceValidator;
import haveno.core.util.validation.InputValidator;
import haveno.desktop.common.view.ActivatableView;
import haveno.desktop.common.view.FxmlView;
@ -313,9 +311,8 @@ public class MobileNotificationsView extends ActivatableView<GridPane, Void> {
TradeCurrency selectedItem = currencyComboBox.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
selectedPriceAlertTradeCurrency = selectedItem.getCode();
boolean isFiatCurrency = CurrencyUtil.isFiatCurrency(selectedPriceAlertTradeCurrency);
priceAlertHighInputTextField.setValidator(isFiatCurrency ? new FiatPriceValidator() : new NonFiatPriceValidator());
priceAlertLowInputTextField.setValidator(isFiatCurrency ? new FiatPriceValidator() : new NonFiatPriceValidator());
priceAlertHighInputTextField.setValidator(PriceUtil.getPriceValidator(selectedPriceAlertTradeCurrency));
priceAlertLowInputTextField.setValidator(PriceUtil.getPriceValidator(selectedPriceAlertTradeCurrency));
} else {
selectedPriceAlertTradeCurrency = null;
}

View file

@ -257,15 +257,15 @@ class OfferBookChartViewModel extends ActivatableViewModel {
}
public int getMaxNumberOfPriceZeroDecimalsToColorize(Offer offer) {
return offer.isFiatOffer()
? GUIUtil.FIAT_DECIMALS_WITH_ZEROS
: GUIUtil.CRYPTOS_DECIMALS_WITH_ZEROS;
return CurrencyUtil.isVolumeRoundedToNearestUnit(offer.getCurrencyCode())
? GUIUtil.NUM_DECIMALS_UNIT
: GUIUtil.NUM_DECIMALS_PRECISE;
}
public int getZeroDecimalsForPrice(Offer offer) {
return offer.isFiatOffer()
? GUIUtil.FIAT_PRICE_DECIMALS_WITH_ZEROS
: GUIUtil.CRYPTOS_DECIMALS_WITH_ZEROS;
return CurrencyUtil.isPricePrecise(offer.getCurrencyCode())
? GUIUtil.NUM_DECIMALS_PRECISE
: GUIUtil.NUM_DECIMALS_PRICE_LESS_PRECISE;
}
public String getPrice(Offer offer) {

View file

@ -32,7 +32,6 @@ import haveno.core.offer.OfferDirection;
import haveno.core.offer.OfferUtil;
import haveno.core.offer.OpenOfferManager;
import haveno.core.payment.PaymentAccount;
import haveno.core.payment.payload.PaymentMethod;
import haveno.core.provider.price.PriceFeedService;
import haveno.core.trade.HavenoUtils;
import haveno.core.trade.handlers.TransactionResultHandler;
@ -685,8 +684,4 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
public void setReserveExactAmount(boolean reserveExactAmount) {
this.reserveExactAmount = reserveExactAmount;
}
public boolean isUsingRoundedAtmCashAccount() {
return PaymentMethod.isRoundedForAtmCash(paymentAccount.getPaymentMethod().getId());
}
}

View file

@ -47,8 +47,8 @@ import haveno.core.util.PriceUtil;
import haveno.core.util.VolumeUtil;
import haveno.core.util.coin.CoinFormatter;
import haveno.core.util.coin.CoinUtil;
import haveno.core.util.validation.NonFiatPriceValidator;
import haveno.core.util.validation.FiatPriceValidator;
import haveno.core.util.validation.AmountValidator8Decimals;
import haveno.core.util.validation.AmountValidator4Decimals;
import haveno.core.util.validation.InputValidator;
import haveno.core.util.validation.MonetaryValidator;
import haveno.core.xmr.wallet.Restrictions;
@ -95,8 +95,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private final Preferences preferences;
protected final CoinFormatter btcFormatter;
private final FiatVolumeValidator fiatVolumeValidator;
private final FiatPriceValidator fiatPriceValidator;
private final NonFiatPriceValidator nonFiatPriceValidator;
private final AmountValidator4Decimals amountValidator4Decimals;
private final AmountValidator8Decimals amountValidator8Decimals;
protected final OfferUtil offerUtil;
private String amountDescription;
@ -184,8 +184,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
@Inject
public MutableOfferViewModel(M dataModel,
FiatVolumeValidator fiatVolumeValidator,
FiatPriceValidator fiatPriceValidator,
NonFiatPriceValidator nonFiatPriceValidator,
AmountValidator4Decimals amountValidator4Decimals,
AmountValidator8Decimals amountValidator8Decimals,
XmrValidator btcValidator,
SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService,
@ -197,8 +197,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
super(dataModel);
this.fiatVolumeValidator = fiatVolumeValidator;
this.fiatPriceValidator = fiatPriceValidator;
this.nonFiatPriceValidator = nonFiatPriceValidator;
this.amountValidator4Decimals = amountValidator4Decimals;
this.amountValidator8Decimals = amountValidator8Decimals;
this.xmrValidator = btcValidator;
this.securityDepositValidator = securityDepositValidator;
this.priceFeedService = priceFeedService;
@ -763,7 +763,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
InputValidator.ValidationResult result = PriceUtil.isTriggerPriceValid(triggerPriceAsString,
marketPrice,
dataModel.isSellOffer(),
dataModel.isTraditionalCurrency()
dataModel.getCurrencyCode()
);
triggerPriceValidationResult.set(result);
updateButtonDisableState();
@ -1175,16 +1175,20 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
return getVolumeValidator().validate(input);
}
// TODO: replace with PriceUtils and VolumeUtils?
private MonetaryValidator getPriceValidator() {
return CurrencyUtil.isFiatCurrency(getTradeCurrency().getCode()) ? fiatPriceValidator : nonFiatPriceValidator;
return CurrencyUtil.isPricePrecise(getTradeCurrency().getCode()) ? amountValidator8Decimals : amountValidator4Decimals;
}
private MonetaryValidator getVolumeValidator() {
final String code = getTradeCurrency().getCode();
if (CurrencyUtil.isFiatCurrency(code)) {
return fiatVolumeValidator;
} else if (CurrencyUtil.isVolumeRoundedToNearestUnit(code)) {
return amountValidator4Decimals;
} else {
return nonFiatPriceValidator;
return amountValidator8Decimals;
}
}

View file

@ -27,8 +27,8 @@ import haveno.core.provider.price.PriceFeedService;
import haveno.core.user.Preferences;
import haveno.core.util.FormattingUtils;
import haveno.core.util.coin.CoinFormatter;
import haveno.core.util.validation.NonFiatPriceValidator;
import haveno.core.util.validation.FiatPriceValidator;
import haveno.core.util.validation.AmountValidator8Decimals;
import haveno.core.util.validation.AmountValidator4Decimals;
import haveno.desktop.Navigation;
import haveno.desktop.common.model.ViewModel;
import haveno.desktop.main.offer.MutableOfferViewModel;
@ -40,8 +40,8 @@ class CreateOfferViewModel extends MutableOfferViewModel<CreateOfferDataModel> i
@Inject
public CreateOfferViewModel(CreateOfferDataModel dataModel,
FiatVolumeValidator fiatVolumeValidator,
FiatPriceValidator fiatPriceValidator,
NonFiatPriceValidator nonFiatPriceValidator,
AmountValidator4Decimals priceValidator4Decimals,
AmountValidator8Decimals priceValidator8Decimals,
XmrValidator btcValidator,
SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService,
@ -52,8 +52,8 @@ class CreateOfferViewModel extends MutableOfferViewModel<CreateOfferDataModel> i
OfferUtil offerUtil) {
super(dataModel,
fiatVolumeValidator,
fiatPriceValidator,
nonFiatPriceValidator,
priceValidator4Decimals,
priceValidator8Decimals,
btcValidator,
securityDepositValidator,
priceFeedService,

View file

@ -427,7 +427,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel {
}
int getNumberOfDecimalsForVolume(OfferBookListItem item) {
return item.getOffer().isFiatOffer() ? GUIUtil.FIAT_DECIMALS_WITH_ZEROS : GUIUtil.CRYPTOS_DECIMALS_WITH_ZEROS;
return CurrencyUtil.isVolumeRoundedToNearestUnit(item.getOffer().getCurrencyCode()) ? GUIUtil.NUM_DECIMALS_UNIT : GUIUtil.NUM_DECIMALS_PRECISE;
}
String getPaymentMethod(OfferBookListItem item) {

View file

@ -311,9 +311,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
if (!isAmountEqualMinAmount(dataModel.getAmount().get()) && (!isAmountEqualMaxAmount(dataModel.getAmount().get()))) {
// We only apply the rounding if the amount is variable (minAmount is lower as amount).
// Otherwise we could get an amount lower then the minAmount set by rounding
BigInteger roundedAmount = dataModel.getOffer().isFiatOffer() ?
CoinUtil.getRoundedFiatAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit) :
CoinUtil.getRoundedTraditionalAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit);
BigInteger roundedAmount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), tradePrice, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
dataModel.applyAmount(roundedAmount);
}
amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get()));
@ -582,9 +580,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
&& !isAmountEqualMinAmount(amount) && !isAmountEqualMaxAmount(amount)) {
// We only apply the rounding if the amount is variable (minAmount is lower as amount).
// Otherwise we could get an amount lower then the minAmount set by rounding
amount = dataModel.getOffer().isFiatOffer() ?
CoinUtil.getRoundedFiatAmount(amount, price, maxTradeLimit) :
CoinUtil.getRoundedTraditionalAmount(amount, price, maxTradeLimit);
amount = CoinUtil.getRoundedAmount(dataModel.getAmount().get(), price, maxTradeLimit, dataModel.getOffer().getCurrencyCode(), dataModel.getOffer().getPaymentMethodId());
}
}
dataModel.applyAmount(amount);

View file

@ -29,8 +29,8 @@ import haveno.core.provider.price.PriceFeedService;
import haveno.core.user.Preferences;
import haveno.core.util.FormattingUtils;
import haveno.core.util.coin.CoinFormatter;
import haveno.core.util.validation.NonFiatPriceValidator;
import haveno.core.util.validation.FiatPriceValidator;
import haveno.core.util.validation.AmountValidator8Decimals;
import haveno.core.util.validation.AmountValidator4Decimals;
import haveno.desktop.Navigation;
import haveno.desktop.main.offer.MutableOfferViewModel;
import lombok.extern.slf4j.Slf4j;
@ -43,8 +43,8 @@ class DuplicateOfferViewModel extends MutableOfferViewModel<DuplicateOfferDataMo
@Inject
public DuplicateOfferViewModel(DuplicateOfferDataModel dataModel,
FiatVolumeValidator fiatVolumeValidator,
FiatPriceValidator fiatPriceValidator,
NonFiatPriceValidator nonFiatPriceValidator,
AmountValidator4Decimals priceValidator4Decimals,
AmountValidator8Decimals priceValidator8Decimals,
XmrValidator btcValidator,
SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService,
@ -55,8 +55,8 @@ class DuplicateOfferViewModel extends MutableOfferViewModel<DuplicateOfferDataMo
OfferUtil offerUtil) {
super(dataModel,
fiatVolumeValidator,
fiatPriceValidator,
nonFiatPriceValidator,
priceValidator4Decimals,
priceValidator8Decimals,
btcValidator,
securityDepositValidator,
priceFeedService,

View file

@ -31,8 +31,8 @@ import haveno.core.user.Preferences;
import haveno.core.util.FormattingUtils;
import haveno.core.util.PriceUtil;
import haveno.core.util.coin.CoinFormatter;
import haveno.core.util.validation.NonFiatPriceValidator;
import haveno.core.util.validation.FiatPriceValidator;
import haveno.core.util.validation.AmountValidator8Decimals;
import haveno.core.util.validation.AmountValidator4Decimals;
import haveno.desktop.Navigation;
import haveno.desktop.main.offer.MutableOfferViewModel;
@ -43,8 +43,8 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> {
@Inject
public EditOfferViewModel(EditOfferDataModel dataModel,
FiatVolumeValidator fiatVolumeValidator,
FiatPriceValidator fiatPriceValidator,
NonFiatPriceValidator nonFiatPriceValidator,
AmountValidator4Decimals priceValidator4Decimals,
AmountValidator8Decimals priceValidator8Decimals,
XmrValidator btcValidator,
SecurityDepositValidator securityDepositValidator,
PriceFeedService priceFeedService,
@ -55,8 +55,8 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> {
OfferUtil offerUtil) {
super(dataModel,
fiatVolumeValidator,
fiatPriceValidator,
nonFiatPriceValidator,
priceValidator4Decimals,
priceValidator8Decimals,
btcValidator,
securityDepositValidator,
priceFeedService,

View file

@ -126,9 +126,9 @@ public class GUIUtil {
public final static String OPEN_WEB_PAGE_KEY = "warnOpenURLWhenTorEnabled";
public final static int FIAT_DECIMALS_WITH_ZEROS = 0;
public final static int FIAT_PRICE_DECIMALS_WITH_ZEROS = 3;
public final static int CRYPTOS_DECIMALS_WITH_ZEROS = 7;
public final static int NUM_DECIMALS_UNIT = 0;
public final static int NUM_DECIMALS_PRICE_LESS_PRECISE = 3;
public final static int NUM_DECIMALS_PRECISE = 7;
public final static int AMOUNT_DECIMALS_WITH_ZEROS = 3;
public final static int AMOUNT_DECIMALS = 4;

View file

@ -39,7 +39,7 @@ public class MarketsPrintTool {
final Collection<TraditionalCurrency> allSortedTraditionalCurrencies = CurrencyUtil.getAllSortedTraditionalCurrencies();
final Stream<MarketCurrency> traditionalStream = allSortedTraditionalCurrencies.stream()
.filter(e -> !e.getCurrency().getCurrencyCode().equals("XMR")) // TODO (woodser): update to XMR
.filter(e -> !e.getCode().equals("XMR"))
.map(e -> new MarketCurrency("xmr_" + e.getCode().toLowerCase(), e.getName(), e.getCode()))
.distinct();

View file

@ -37,8 +37,8 @@ import haveno.core.user.Preferences;
import haveno.core.user.User;
import haveno.core.util.coin.CoinFormatter;
import haveno.core.util.coin.ImmutableCoinFormatter;
import haveno.core.util.validation.NonFiatPriceValidator;
import haveno.core.util.validation.FiatPriceValidator;
import haveno.core.util.validation.AmountValidator8Decimals;
import haveno.core.util.validation.AmountValidator4Decimals;
import haveno.core.util.validation.InputValidator;
import haveno.core.xmr.model.XmrAddressEntry;
import haveno.core.xmr.wallet.XmrWalletService;
@ -72,8 +72,8 @@ public class CreateOfferViewModelTest {
Res.setup();
final XmrValidator btcValidator = new XmrValidator();
final NonFiatPriceValidator nonFiatPriceValidator = new NonFiatPriceValidator();
final FiatPriceValidator fiatPriceValidator = new FiatPriceValidator();
final AmountValidator8Decimals priceValidator8Decimals = new AmountValidator8Decimals();
final AmountValidator4Decimals priceValidator4Decimals = new AmountValidator4Decimals();
XmrAddressEntry addressEntry = mock(XmrAddressEntry.class);
XmrWalletService xmrWalletService = mock(XmrWalletService.class);
@ -121,8 +121,8 @@ public class CreateOfferViewModelTest {
model = new CreateOfferViewModel(dataModel,
null,
fiatPriceValidator,
nonFiatPriceValidator,
priceValidator4Decimals,
priceValidator8Decimals,
btcValidator,
securityDepositValidator,
priceFeedService,

View file

@ -1786,7 +1786,6 @@ message CryptoCurrency {
}
message TraditionalCurrency {
Currency currency = 1;
}
message Country {